#include "base/profiler/module_cache.h"
#include <algorithm>
#include <iterator>
#include <string_view>
#include <utility>
#include "base/check_op.h"
#include "base/strings/strcat.h"
namespace base {
namespace {
struct ModuleAddressCompare {
bool operator()(const std::unique_ptr<const ModuleCache::Module>& module,
uintptr_t address) const {
return module->GetBaseAddress() + module->GetSize() <= address;
}
bool operator()(
uintptr_t address,
const std::unique_ptr<const ModuleCache::Module>& module) const {
return address < module->GetBaseAddress();
}
};
}
std::string TransformModuleIDToSymbolServerFormat(std::string_view module_id) {
std::string mangled_id(module_id);
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX)
if (mangled_id.size() < 32) {
mangled_id.resize(32, '0');
}
mangled_id = base::StrCat({mangled_id.substr(6, 2), mangled_id.substr(4, 2),
mangled_id.substr(2, 2), mangled_id.substr(0, 2),
mangled_id.substr(10, 2), mangled_id.substr(8, 2),
mangled_id.substr(14, 2), mangled_id.substr(12, 2),
mangled_id.substr(16, 16), "0"});
#endif
return mangled_id;
}
ModuleCache::ModuleCache() = default;
ModuleCache::~ModuleCache() {
DCHECK_EQ(auxiliary_module_provider_, nullptr);
}
const ModuleCache::Module* ModuleCache::GetModuleForAddress(uintptr_t address) {
if (const ModuleCache::Module* module =
GetExistingModuleForAddress(address)) {
return module;
}
std::unique_ptr<const Module> new_module = CreateModuleForAddress(address);
if (!new_module && auxiliary_module_provider_) {
new_module = auxiliary_module_provider_->TryCreateModuleForAddress(address);
}
if (!new_module) {
return nullptr;
}
const auto result = native_modules_.insert(std::move(new_module));
return result.first->get();
}
std::vector<const ModuleCache::Module*> ModuleCache::GetModules() const {
std::vector<const Module*> result;
result.reserve(native_modules_.size());
for (const std::unique_ptr<const Module>& module : native_modules_) {
result.push_back(module.get());
}
base::AutoLock locker(lock_);
for (const std::unique_ptr<const Module>& module : non_native_modules_) {
result.push_back(module.get());
}
return result;
}
void ModuleCache::UpdateNonNativeModules(
const std::vector<const Module*>& defunct_modules,
std::vector<std::unique_ptr<const Module>> new_modules) {
flat_set<const Module*> defunct_modules_set(defunct_modules.begin(),
defunct_modules.end());
base::AutoLock locker(lock_);
auto defunct_modules_subrange = std::ranges::stable_partition(
non_native_modules_,
[&defunct_modules_set](const std::unique_ptr<const Module>& module) {
return defunct_modules_set.find(module.get()) ==
defunct_modules_set.end();
});
DCHECK_EQ(defunct_modules.size(), defunct_modules_subrange.size());
inactive_non_native_modules_.insert(
inactive_non_native_modules_.end(),
std::make_move_iterator(defunct_modules_subrange.begin()),
std::make_move_iterator(defunct_modules_subrange.end()));
non_native_modules_.erase(defunct_modules_subrange.begin(),
defunct_modules_subrange.end());
const size_t prior_non_native_modules_size = non_native_modules_.size();
non_native_modules_.insert(std::make_move_iterator(new_modules.begin()),
std::make_move_iterator(new_modules.end()));
CHECK_EQ(prior_non_native_modules_size + new_modules.size(),
non_native_modules_.size());
}
void ModuleCache::AddCustomNativeModule(std::unique_ptr<const Module> module) {
const bool was_inserted = native_modules_.insert(std::move(module)).second;
CHECK(was_inserted);
}
const ModuleCache::Module* ModuleCache::GetExistingModuleForAddress(
uintptr_t address) const {
{
base::AutoLock locker(lock_);
const auto non_native_module_loc = non_native_modules_.find(address);
if (non_native_module_loc != non_native_modules_.end()) {
return non_native_module_loc->get();
}
}
const auto native_module_loc = native_modules_.find(address);
if (native_module_loc != native_modules_.end()) {
return native_module_loc->get();
}
return nullptr;
}
void ModuleCache::RegisterAuxiliaryModuleProvider(
AuxiliaryModuleProvider* auxiliary_module_provider) {
DCHECK(!auxiliary_module_provider_);
auxiliary_module_provider_ = auxiliary_module_provider;
}
void ModuleCache::UnregisterAuxiliaryModuleProvider(
AuxiliaryModuleProvider* auxiliary_module_provider) {
DCHECK_EQ(auxiliary_module_provider_, auxiliary_module_provider);
auxiliary_module_provider_ = nullptr;
}
bool ModuleCache::ModuleAndAddressCompare::operator()(
const std::unique_ptr<const Module>& m1,
const std::unique_ptr<const Module>& m2) const {
return m1->GetBaseAddress() < m2->GetBaseAddress();
}
bool ModuleCache::ModuleAndAddressCompare::operator()(
const std::unique_ptr<const Module>& m1,
uintptr_t address) const {
return m1->GetBaseAddress() + m1->GetSize() <= address;
}
bool ModuleCache::ModuleAndAddressCompare::operator()(
uintptr_t address,
const std::unique_ptr<const Module>& m2) const {
return address < m2->GetBaseAddress();
}
}