module_cache.cc 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/profiler/module_cache.h"
  5. #include <iterator>
  6. #include <utility>
  7. #include "base/check_op.h"
  8. #include "base/ranges/algorithm.h"
  9. #include "base/strings/strcat.h"
  10. namespace base {
  11. namespace {
  12. // Supports heterogeneous comparisons on modules and addresses, for use in
  13. // binary searching modules sorted by range for a contained address.
  14. struct ModuleAddressCompare {
  15. bool operator()(const std::unique_ptr<const ModuleCache::Module>& module,
  16. uintptr_t address) const {
  17. return module->GetBaseAddress() + module->GetSize() <= address;
  18. }
  19. bool operator()(
  20. uintptr_t address,
  21. const std::unique_ptr<const ModuleCache::Module>& module) const {
  22. return address < module->GetBaseAddress();
  23. }
  24. };
  25. } // namespace
  26. std::string TransformModuleIDToBreakpadFormat(StringPiece module_id) {
  27. std::string mangled_id(module_id);
  28. #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  29. // Linux ELF module IDs are 160bit integers, which we need to mangle
  30. // down to 128bit integers to match the id that Breakpad outputs.
  31. // Example on version '66.0.3359.170' x64:
  32. // Build-ID: "7f0715c2 86f8 b16c 10e4ad349cda3b9b 56c7a773
  33. // Debug-ID "C215077F F886 6CB1 10E4AD349CDA3B9B 0"
  34. if (mangled_id.size() < 32) {
  35. mangled_id.resize(32, '0');
  36. }
  37. mangled_id = base::StrCat({mangled_id.substr(6, 2), mangled_id.substr(4, 2),
  38. mangled_id.substr(2, 2), mangled_id.substr(0, 2),
  39. mangled_id.substr(10, 2), mangled_id.substr(8, 2),
  40. mangled_id.substr(14, 2), mangled_id.substr(12, 2),
  41. mangled_id.substr(16, 16), "0"});
  42. #endif
  43. return mangled_id;
  44. }
  45. ModuleCache::ModuleCache() = default;
  46. ModuleCache::~ModuleCache() {
  47. DCHECK_EQ(auxiliary_module_provider_, nullptr);
  48. }
  49. const ModuleCache::Module* ModuleCache::GetModuleForAddress(uintptr_t address) {
  50. if (const ModuleCache::Module* module = GetExistingModuleForAddress(address))
  51. return module;
  52. std::unique_ptr<const Module> new_module = CreateModuleForAddress(address);
  53. if (!new_module && auxiliary_module_provider_)
  54. new_module = auxiliary_module_provider_->TryCreateModuleForAddress(address);
  55. if (!new_module)
  56. return nullptr;
  57. const auto result = native_modules_.insert(std::move(new_module));
  58. // TODO(https://crbug.com/1131769): Reintroduce DCHECK(result.second) after
  59. // fixing the issue that is causing it to fail.
  60. return result.first->get();
  61. }
  62. std::vector<const ModuleCache::Module*> ModuleCache::GetModules() const {
  63. std::vector<const Module*> result;
  64. result.reserve(native_modules_.size());
  65. for (const std::unique_ptr<const Module>& module : native_modules_)
  66. result.push_back(module.get());
  67. for (const std::unique_ptr<const Module>& module : non_native_modules_)
  68. result.push_back(module.get());
  69. return result;
  70. }
  71. void ModuleCache::UpdateNonNativeModules(
  72. const std::vector<const Module*>& defunct_modules,
  73. std::vector<std::unique_ptr<const Module>> new_modules) {
  74. // Insert the modules to remove into a set to support O(log(n)) lookup below.
  75. flat_set<const Module*> defunct_modules_set(defunct_modules.begin(),
  76. defunct_modules.end());
  77. // Reorder the modules to be removed to the last slots in the set, then move
  78. // them to the inactive modules, then erase the moved-from modules from the
  79. // set. This is a variation on the standard erase-remove idiom, which is
  80. // explicitly endorsed for implementing erase behavior on flat_sets.
  81. //
  82. // stable_partition is O(m*log(r)) where m is the number of current modules
  83. // and r is the number of modules to remove. insert and erase are both O(r).
  84. auto first_module_defunct_modules = ranges::stable_partition(
  85. non_native_modules_,
  86. [&defunct_modules_set](const std::unique_ptr<const Module>& module) {
  87. return defunct_modules_set.find(module.get()) ==
  88. defunct_modules_set.end();
  89. });
  90. // All modules requested to be removed should have been found.
  91. DCHECK_EQ(
  92. static_cast<ptrdiff_t>(defunct_modules.size()),
  93. std::distance(first_module_defunct_modules, non_native_modules_.end()));
  94. inactive_non_native_modules_.insert(
  95. inactive_non_native_modules_.end(),
  96. std::make_move_iterator(first_module_defunct_modules),
  97. std::make_move_iterator(non_native_modules_.end()));
  98. non_native_modules_.erase(first_module_defunct_modules,
  99. non_native_modules_.end());
  100. // Insert the modules to be added. This operation is O((m + a) + a*log(a))
  101. // where m is the number of current modules and a is the number of modules to
  102. // be added.
  103. const size_t prior_non_native_modules_size = non_native_modules_.size();
  104. non_native_modules_.insert(std::make_move_iterator(new_modules.begin()),
  105. std::make_move_iterator(new_modules.end()));
  106. // Every module in |new_modules| should have been moved into
  107. // |non_native_modules_|. This guards against use-after-frees if |new_modules|
  108. // were to contain any modules equivalent to what's already in
  109. // |non_native_modules_|, in which case the module would remain in
  110. // |new_modules| and be deleted on return from the function. While this
  111. // scenario would be a violation of the API contract, it would present a
  112. // difficult-to-track-down crash scenario.
  113. CHECK_EQ(prior_non_native_modules_size + new_modules.size(),
  114. non_native_modules_.size());
  115. }
  116. void ModuleCache::AddCustomNativeModule(std::unique_ptr<const Module> module) {
  117. const bool was_inserted = native_modules_.insert(std::move(module)).second;
  118. // |module| should have been inserted into |native_modules_|, indicating that
  119. // there was no equivalent module already present. While this scenario would
  120. // be a violation of the API contract, it would present a
  121. // difficult-to-track-down crash scenario.
  122. CHECK(was_inserted);
  123. }
  124. const ModuleCache::Module* ModuleCache::GetExistingModuleForAddress(
  125. uintptr_t address) const {
  126. const auto non_native_module_loc = non_native_modules_.find(address);
  127. if (non_native_module_loc != non_native_modules_.end())
  128. return non_native_module_loc->get();
  129. const auto native_module_loc = native_modules_.find(address);
  130. if (native_module_loc != native_modules_.end())
  131. return native_module_loc->get();
  132. return nullptr;
  133. }
  134. void ModuleCache::RegisterAuxiliaryModuleProvider(
  135. AuxiliaryModuleProvider* auxiliary_module_provider) {
  136. DCHECK(!auxiliary_module_provider_);
  137. auxiliary_module_provider_ = auxiliary_module_provider;
  138. }
  139. void ModuleCache::UnregisterAuxiliaryModuleProvider(
  140. AuxiliaryModuleProvider* auxiliary_module_provider) {
  141. DCHECK_EQ(auxiliary_module_provider_, auxiliary_module_provider);
  142. auxiliary_module_provider_ = nullptr;
  143. }
  144. bool ModuleCache::ModuleAndAddressCompare::operator()(
  145. const std::unique_ptr<const Module>& m1,
  146. const std::unique_ptr<const Module>& m2) const {
  147. return m1->GetBaseAddress() < m2->GetBaseAddress();
  148. }
  149. bool ModuleCache::ModuleAndAddressCompare::operator()(
  150. const std::unique_ptr<const Module>& m1,
  151. uintptr_t address) const {
  152. return m1->GetBaseAddress() + m1->GetSize() <= address;
  153. }
  154. bool ModuleCache::ModuleAndAddressCompare::operator()(
  155. uintptr_t address,
  156. const std::unique_ptr<const Module>& m2) const {
  157. return address < m2->GetBaseAddress();
  158. }
  159. } // namespace base