diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2020-04-28 20:26:44 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2020-04-28 20:26:44 +0000 |
commit | 30a4df025ab854a247b9714fbf6840bd7f8211fd (patch) | |
tree | 8c64e6ae9306cdbdbda36580bc247a36a051e1fa /perfprofd/symbolizer.cc | |
parent | c36ecc0803cb1df95f2daf90b100370f0631f9fb (diff) | |
parent | 29e06f5526a2dd48c9f19ef7f238804f84c03c30 (diff) | |
download | extras-30a4df025ab854a247b9714fbf6840bd7f8211fd.tar.gz |
Snap for 6439596 from 29e06f5526a2dd48c9f19ef7f238804f84c03c30 to qt-aml-tzdata-releaseq_tzdata_aml_297100400q_tzdata_aml_297100300q_tzdata_aml_297100000q_tzdata_aml_296200000q_tzdata_aml_295600118q_tzdata_aml_295600110q_tzdata_aml_295500002q_tzdata_aml_295500001q_tzdata_aml_294400310android-mainline-12.0.0_r54android-mainline-12.0.0_r111android-mainline-10.0.0_r13android-mainline-10.0.0_r12android-mainline-10.0.0_r11q_tzdata_aml_297100000android12-mainline-tzdata-releaseandroid10-mainline-tzdata-releaseandroid10-android13-mainline-tzdata-release
Change-Id: Ie3b2616d0777d5fa31840df0790cc48856698478
Diffstat (limited to 'perfprofd/symbolizer.cc')
-rw-r--r-- | perfprofd/symbolizer.cc | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/perfprofd/symbolizer.cc b/perfprofd/symbolizer.cc new file mode 100644 index 00000000..3b39f6f5 --- /dev/null +++ b/perfprofd/symbolizer.cc @@ -0,0 +1,179 @@ +/* + * + * Copyright 2018, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "symbolizer.h" + +#include <map> +#include <memory> +#include <unordered_map> + +#include <android-base/logging.h> +#include <base/mem_map.h> +#include <build_id.h> +#include <read_dex_file.h> +#include <read_elf.h> +#include <vdex_file.h> + +namespace perfprofd { + +namespace { + +struct SimpleperfSymbolizer : public Symbolizer { + // For simplicity, we assume non-overlapping symbols. + struct Symbol { + Symbol(std::string_view n, uint64_t l) : name(n), length(l) {} + + std::string name; + uint64_t length; + }; + using SymbolMap = std::map<uint64_t, Symbol>; + + std::string Decode(const std::string& dso, uint64_t address) override { + auto it = dsos.find(dso); + if (it == dsos.end()) { + LoadDso(dso); + it = dsos.find(dso); + DCHECK(it != dsos.end()); + } + + const SymbolMap& map = it->second; + if (map.empty()) { + return ""; + } + auto upper_bound = map.upper_bound(address); + if (upper_bound == map.begin()) { + // Nope, not in the map. + return ""; + } + + upper_bound--; + if (upper_bound->first + upper_bound->second.length > address) { + // This element covers the given address, return its name. + return upper_bound->second.name; + } + + return ""; + } + + void LoadDso(const std::string& dso) { + // See whether it's an ELF file. + { + SymbolMap elf_data; + auto callback = [&elf_data](const ElfFileSymbol& sym) { + if (sym.is_func) { + if (sym.len == 0) { + LOG(ERROR) << "Symbol size is zero for " << sym.name; + } + elf_data.emplace(sym.vaddr, Symbol(sym.name, sym.len)); + } + }; + ElfStatus status = ParseSymbolsFromElfFile(dso, BuildId(), callback); + if (status == ElfStatus::NO_ERROR) { + dsos.emplace(dso, std::move(elf_data)); + return; + } + } + + // See whether it's a vdex file. + { + ::art::MemMap::Init(); + + using VdexFile = ::art::VdexFile; + std::string error_msg; + std::unique_ptr<VdexFile> vdex = VdexFile::Open(dso, + /* writable= */ false, + /* low_4gb= */ false, + /* unquicken= */ false, + &error_msg); + if (vdex != nullptr) { + const uint8_t* cur = nullptr; + std::vector<uint64_t> dex_file_offsets; + const uint8_t* base = vdex->Begin(); + for (;;) { + cur = vdex->GetNextDexFileData(cur); + if (cur == nullptr) { + break; + } + dex_file_offsets.push_back(cur - base); + } + + if (!dex_file_offsets.empty()) { + std::vector<DexFileSymbol> symbols; + if (ReadSymbolsFromDexFile(dso, dex_file_offsets, &symbols)) { + SymbolMap vdex_data; + for (const DexFileSymbol& symbol : symbols) { + vdex_data.emplace(symbol.offset, Symbol(symbol.name, symbol.len)); + } + dsos.emplace(dso, std::move(vdex_data)); + LOG(INFO) << "Found " << symbols.size() << " dex symbols in " << dso; + return; + } else { + LOG(WARNING) << "Could not read symbols from dex files in " << dso; + } + } else { + LOG(WARNING) << "Could not find dex files for vdex " << dso; + dsos.emplace(dso, SymbolMap()); + } + } else { + LOG(WARNING) << dso << " is not a vdex: " << error_msg; + } + } + + // TODO: See whether it's a dex file. + + // OK, give up. + LOG(WARNING) << "Could not symbolize " << dso; + dsos.emplace(dso, SymbolMap()); + } + + bool GetMinExecutableVAddr(const std::string& dso, uint64_t* addr) override { + uint64_t file_offset_of_min_vaddr; + ElfStatus status = ReadMinExecutableVirtualAddressFromElfFile(dso, BuildId(), addr, + &file_offset_of_min_vaddr); + if (status != ElfStatus::NO_ERROR) { + return true; + } + + { + ::art::MemMap::Init(); + + using VdexFile = ::art::VdexFile; + std::string error_msg; + std::unique_ptr<VdexFile> vdex = VdexFile::Open(dso, + /* writable= */ false, + /* low_4gb= */ false, + /* unquicken= */ false, + &error_msg); + if (vdex != nullptr) { + *addr = 0u; + return true; + } + } + + return false; + } + + std::unordered_map<std::string, SymbolMap> dsos; +}; + +} // namespace + +std::unique_ptr<Symbolizer> CreateELFSymbolizer() { + return std::unique_ptr<Symbolizer>(new SimpleperfSymbolizer()); +} + +} // namespace perfprofd |