#include "base/profiler/module_cache.h"
#include <dlfcn.h>
#include <elf.h>
#include <optional>
#include <string_view>
#include "base/debug/elf_reader.h"
#include "build/build_config.h"
#if BUILDFLAG(IS_ANDROID)
extern "C" {
extern const char __executable_start;
extern const char _etext;
}
#endif
namespace base {
namespace {
std::string GetUniqueBuildId(const void* module_addr) {
debug::ElfBuildIdBuffer build_id;
size_t build_id_length = debug::ReadElfBuildId(module_addr, true, build_id);
if (!build_id_length) {
return std::string();
}
return std::string(build_id, build_id_length) + "0";
}
size_t GetLastExecutableOffset(const void* module_addr) {
const size_t relocation_offset = debug::GetRelocationOffset(module_addr);
size_t max_offset = 0;
for (const Phdr& header : debug::GetElfProgramHeaders(module_addr)) {
if (header.p_type != PT_LOAD || !(header.p_flags & PF_X)) {
continue;
}
max_offset = std::max(
max_offset, static_cast<size_t>(
header.p_vaddr + relocation_offset + header.p_memsz -
reinterpret_cast<uintptr_t>(module_addr)));
}
return max_offset;
}
FilePath GetDebugBasenameForModule(const void* base_address,
std::string_view file) {
#if BUILDFLAG(IS_ANDROID)
std::optional<std::string_view> library_name =
debug::ReadElfLibraryName(base_address);
if (library_name) {
return FilePath(*library_name);
}
#endif
#if BUILDFLAG(IS_CHROMEOS)
size_t pos = file.find(" --");
if (pos != std::string_view::npos) {
file = file.substr(0, pos);
}
#endif
return FilePath(file).BaseName();
}
class PosixModule : public ModuleCache::Module {
public:
PosixModule(uintptr_t base_address,
const std::string& build_id,
const FilePath& debug_basename,
size_t size);
PosixModule(const PosixModule&) = delete;
PosixModule& operator=(const PosixModule&) = delete;
uintptr_t GetBaseAddress() const override { return base_address_; }
std::string GetId() const override { return id_; }
FilePath GetDebugBasename() const override { return debug_basename_; }
size_t GetSize() const override { return size_; }
bool IsNative() const override { return true; }
private:
uintptr_t base_address_;
std::string id_;
FilePath debug_basename_;
size_t size_;
};
PosixModule::PosixModule(uintptr_t base_address,
const std::string& build_id,
const FilePath& debug_basename,
size_t size)
: base_address_(base_address),
id_(build_id),
debug_basename_(debug_basename),
size_(size) {}
}
std::unique_ptr<const ModuleCache::Module> ModuleCache::CreateModuleForAddress(
uintptr_t address) {
Dl_info info;
if (!dladdr(reinterpret_cast<const void*>(address), &info)) {
#if BUILDFLAG(IS_ANDROID)
if (address >= reinterpret_cast<uintptr_t>(&__executable_start) &&
address < reinterpret_cast<uintptr_t>(&_etext)) {
const void* const base_address =
reinterpret_cast<const void*>(&__executable_start);
return std::make_unique<PosixModule>(
reinterpret_cast<uintptr_t>(&__executable_start),
GetUniqueBuildId(base_address),
GetDebugBasenameForModule(base_address, ""),
GetLastExecutableOffset(base_address));
}
#endif
return nullptr;
}
return std::make_unique<PosixModule>(
reinterpret_cast<uintptr_t>(info.dli_fbase),
GetUniqueBuildId(info.dli_fbase),
GetDebugBasenameForModule(info.dli_fbase, info.dli_fname),
GetLastExecutableOffset(info.dli_fbase));
}
}