1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include "ETMDecoder.h" 20 #include "RegEx.h" 21 #include "thread_tree.h" 22 #include "utils.h" 23 24 namespace simpleperf { 25 26 // When processing binary info in an input file, the binaries are identified by their path. 27 // But this isn't sufficient when merging binary info from multiple input files. Because 28 // binaries for the same path may be changed between generating input files. So after processing 29 // each input file, we create BinaryKeys to identify binaries, which consider path, build_id and 30 // kernel_start_addr (for vmlinux). kernel_start_addr affects how addresses in BranchListBinaryInfo 31 // are interpreted for vmlinux. 32 struct BinaryKey { 33 std::string path; 34 BuildId build_id; 35 uint64_t kernel_start_addr = 0; 36 BinaryKeyBinaryKey37 BinaryKey() {} 38 BinaryKeyBinaryKey39 BinaryKey(const std::string& path, BuildId build_id) : path(path), build_id(build_id) {} 40 BinaryKeyBinaryKey41 BinaryKey(Dso* dso, uint64_t kernel_start_addr) : path(dso->Path()) { 42 build_id = Dso::FindExpectedBuildIdForPath(dso->Path()); 43 if (dso->type() == DSO_KERNEL) { 44 this->kernel_start_addr = kernel_start_addr; 45 } 46 } 47 48 bool operator==(const BinaryKey& other) const { 49 return path == other.path && build_id == other.build_id && 50 kernel_start_addr == other.kernel_start_addr; 51 } 52 }; 53 54 struct BinaryKeyHash { operatorBinaryKeyHash55 size_t operator()(const BinaryKey& key) const noexcept { 56 size_t seed = 0; 57 HashCombine(seed, key.path); 58 HashCombine(seed, key.build_id); 59 if (key.kernel_start_addr != 0) { 60 HashCombine(seed, key.kernel_start_addr); 61 } 62 return seed; 63 } 64 }; 65 66 using UnorderedBranchMap = 67 std::unordered_map<uint64_t, std::unordered_map<std::vector<bool>, uint64_t>>; 68 69 struct BranchListBinaryInfo { 70 DsoType dso_type; 71 UnorderedBranchMap branch_map; 72 MergeBranchListBinaryInfo73 void Merge(const BranchListBinaryInfo& other) { 74 for (auto& other_p : other.branch_map) { 75 auto it = branch_map.find(other_p.first); 76 if (it == branch_map.end()) { 77 branch_map[other_p.first] = std::move(other_p.second); 78 } else { 79 auto& map2 = it->second; 80 for (auto& other_p2 : other_p.second) { 81 auto it2 = map2.find(other_p2.first); 82 if (it2 == map2.end()) { 83 map2[other_p2.first] = other_p2.second; 84 } else { 85 OverflowSafeAdd(it2->second, other_p2.second); 86 } 87 } 88 } 89 } 90 } 91 GetOrderedBranchMapBranchListBinaryInfo92 BranchMap GetOrderedBranchMap() const { 93 BranchMap result; 94 for (const auto& p : branch_map) { 95 uint64_t addr = p.first; 96 const auto& b_map = p.second; 97 result[addr] = std::map<std::vector<bool>, uint64_t>(b_map.begin(), b_map.end()); 98 } 99 return result; 100 } 101 }; 102 103 using BranchListBinaryMap = std::unordered_map<BinaryKey, BranchListBinaryInfo, BinaryKeyHash>; 104 105 bool BranchListBinaryMapToString(const BranchListBinaryMap& binary_map, std::string& s); 106 bool StringToBranchListBinaryMap(const std::string& s, BranchListBinaryMap& binary_map); 107 108 class BinaryFilter { 109 public: BinaryFilter(const RegEx * binary_name_regex)110 BinaryFilter(const RegEx* binary_name_regex) : binary_name_regex_(binary_name_regex) {} 111 SetRegex(const RegEx * binary_name_regex)112 void SetRegex(const RegEx* binary_name_regex) { 113 binary_name_regex_ = binary_name_regex; 114 dso_filter_cache_.clear(); 115 } 116 Filter(Dso * dso)117 bool Filter(Dso* dso) { 118 auto lookup = dso_filter_cache_.find(dso); 119 if (lookup != dso_filter_cache_.end()) { 120 return lookup->second; 121 } 122 bool match = Filter(dso->Path()); 123 dso_filter_cache_.insert({dso, match}); 124 return match; 125 } 126 Filter(const std::string & path)127 bool Filter(const std::string& path) { 128 return binary_name_regex_ == nullptr || binary_name_regex_->Search(path); 129 } 130 131 private: 132 const RegEx* binary_name_regex_; 133 std::unordered_map<Dso*, bool> dso_filter_cache_; 134 }; 135 136 // Convert ETM data into branch lists while recording. 137 class ETMBranchListGenerator { 138 public: 139 static std::unique_ptr<ETMBranchListGenerator> Create(bool dump_maps_from_proc); 140 141 virtual ~ETMBranchListGenerator(); 142 virtual void SetExcludePid(pid_t pid) = 0; 143 virtual void SetBinaryFilter(const RegEx* binary_name_regex) = 0; 144 virtual bool ProcessRecord(const Record& r, bool& consumed) = 0; 145 virtual BranchListBinaryMap GetBranchListBinaryMap() = 0; 146 }; 147 148 // for testing 149 std::string BranchToProtoString(const std::vector<bool>& branch); 150 std::vector<bool> ProtoStringToBranch(const std::string& s, size_t bit_size); 151 152 } // namespace simpleperf 153