1 2 /* 3 * Copyright (C) 2024 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_VIRTUAL_MEMORY_MAPPING_H_ 19 #define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_VIRTUAL_MEMORY_MAPPING_H_ 20 21 #include <cstddef> 22 #include <cstdint> 23 #include <optional> 24 #include <string> 25 #include <vector> 26 27 #include "perfetto/ext/base/flat_hash_map.h" 28 #include "perfetto/ext/base/hash.h" 29 #include "perfetto/ext/base/string_view.h" 30 #include "src/trace_processor/importers/common/address_range.h" 31 #include "src/trace_processor/importers/common/create_mapping_params.h" 32 #include "src/trace_processor/storage/trace_storage.h" 33 #include "src/trace_processor/types/trace_processor_context.h" 34 #include "src/trace_processor/util/build_id.h" 35 36 namespace perfetto { 37 namespace trace_processor { 38 39 // TODO(carlscab): Reconsider whether jit is the best abstraction here. All we 40 // really care is about mapping a `rel_pc` to a symbol (aka symbolization) and 41 // whether is this is constant. 42 class JitCache; 43 44 // Represents a mapping in virtual memory. 45 class VirtualMemoryMapping { 46 public: 47 virtual ~VirtualMemoryMapping(); 48 // Range of virtual memory this mapping covers. memory_range()49 AddressRange memory_range() const { return memory_range_; } mapping_id()50 MappingId mapping_id() const { return mapping_id_; } 51 // This name could be the path of the underlying file mapped into memory. name()52 const std::string& name() const { return name_; } 53 // For file mappings, this is the offset into the file for the first byte in 54 // the mapping offset()55 uint64_t offset() const { return offset_; } 56 // If the mapped file is an executable or shared library this will return the 57 // load bias, if known. Returns 0 otherwise. load_bias()58 uint64_t load_bias() const { return load_bias_; } 59 // If the mapped file is an executable or shared library this will return its 60 // build id, if known. build_id()61 const std::optional<BuildId>& build_id() const { return build_id_; } 62 63 // Whether this maps to a region that holds jitted code. is_jitted()64 bool is_jitted() const { return jit_cache_ != nullptr; } 65 66 // Converts an absolute address into a relative one. ToRelativePc(uint64_t address)67 uint64_t ToRelativePc(uint64_t address) const { 68 return address - memory_range_.start() + offset_ + load_bias_; 69 } 70 71 // Converts a relative address to an absolute one. ToAddress(uint64_t rel_pc)72 uint64_t ToAddress(uint64_t rel_pc) const { 73 return rel_pc + (memory_range_.start() - offset_ - load_bias_); 74 } 75 76 // Creates a frame for the given `rel_pc`. Note that if the mapping 77 // `is_jitted()` same `rel_pc` values can return different mappings (as jitted 78 // functions can be created and deleted over time.) So for such mappings the 79 // returned `FrameId` should not be cached. 80 FrameId InternFrame(uint64_t rel_pc, base::StringView function_name); 81 82 // Returns all frames ever created in this mapping for the given `rel_pc`. 83 std::vector<FrameId> FindFrameIds(uint64_t rel_pc) const; 84 85 protected: 86 VirtualMemoryMapping(TraceProcessorContext* context, 87 CreateMappingParams params); 88 89 private: 90 friend class MappingTracker; 91 92 std::pair<FrameId, bool> InternFrameImpl(uint64_t rel_pc, 93 base::StringView function_name); 94 SetJitCache(JitCache * jit_cache)95 void SetJitCache(JitCache* jit_cache) { jit_cache_ = jit_cache; } 96 97 TraceProcessorContext* const context_; 98 const MappingId mapping_id_; 99 const AddressRange memory_range_; 100 const uint64_t offset_; 101 const uint64_t load_bias_; 102 const std::string name_; 103 std::optional<BuildId> const build_id_; 104 JitCache* jit_cache_ = nullptr; 105 106 struct FrameKey { 107 uint64_t rel_pc; 108 // It doesn't seem to make too much sense to key on name, as for the same 109 // mapping and same rel_pc the name should always be the same. But who knows 110 // how producers behave. 111 StringId name_id; 112 113 bool operator==(const FrameKey& o) const { 114 return rel_pc == o.rel_pc && name_id == o.name_id; 115 } 116 117 struct Hasher { operatorFrameKey::Hasher118 size_t operator()(const FrameKey& k) const { 119 return static_cast<size_t>( 120 base::Hasher::Combine(k.rel_pc, k.name_id.raw_id())); 121 } 122 }; 123 }; 124 base::FlatHashMap<FrameKey, FrameId, FrameKey::Hasher> interned_frames_; 125 base::FlatHashMap<uint64_t, std::vector<FrameId>> frames_by_rel_pc_; 126 }; 127 128 class KernelMemoryMapping : public VirtualMemoryMapping { 129 public: 130 ~KernelMemoryMapping() override; 131 132 private: 133 friend class MappingTracker; 134 KernelMemoryMapping(TraceProcessorContext* context, 135 CreateMappingParams params); 136 }; 137 138 class UserMemoryMapping : public VirtualMemoryMapping { 139 public: 140 ~UserMemoryMapping() override; upid()141 UniquePid upid() const { return upid_; } 142 143 private: 144 friend class MappingTracker; 145 UserMemoryMapping(TraceProcessorContext* context, 146 UniquePid upid, 147 CreateMappingParams params); 148 149 const UniquePid upid_; 150 }; 151 152 } // namespace trace_processor 153 } // namespace perfetto 154 155 #endif // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_VIRTUAL_MEMORY_MAPPING_H_ 156