The C in DSC. This represents the entire cache, all regions and images are visible from here. This is the dump for all the information, and what the workflow activities and the UI want. Creating this is expensive, both in actual processing and just copying, so we only generate this once every time the database is open.
| 169 | // Creating this is expensive, both in actual processing and just copying, so we only generate this |
| 170 | // once every time the database is open. |
| 171 | class SharedCache |
| 172 | { |
| 173 | // Calculated within `AddEntry`, this indicates where the shared cache image is based at. |
| 174 | uint64_t m_baseAddress = 0; |
| 175 | // The shared cache can own the virtual memory, this is fine... |
| 176 | std::shared_ptr<VirtualMemory> m_vm; |
| 177 | std::vector<CacheEntry> m_entries {}; |
| 178 | // This information is used in tandem with the cache images to load memory regions into the binary view. |
| 179 | AddressRangeMap<CacheRegion> m_regions {}; |
| 180 | // Describes the images of the cache. |
| 181 | std::unordered_map<uint64_t, CacheImage> m_images {}; |
| 182 | // All the external symbols for this cache. Both mapped and unmapped (not in the view). |
| 183 | std::unordered_map<uint64_t, CacheSymbol> m_symbols {}; |
| 184 | // Quickly lookup a symbol by name, populated by `FinalizeSymbols`. |
| 185 | // `m_namedSymbols` is modified in a worker thread spawned by view init so we must not get a symbol until its populated. |
| 186 | std::unordered_map<std::string, uint64_t> m_namedSymbols {}; |
| 187 | // Used to guard `m_namedSymbols` as it's accessed on multiple threads. |
| 188 | // NOTE: Wrapped in unique_ptr to keep SharedCache movable. |
| 189 | std::unique_ptr<std::shared_mutex> m_namedSymMutex; |
| 190 | |
| 191 | bool ProcessEntryImage(const std::string& path, const dyld_cache_image_info& info); |
| 192 | |
| 193 | // Add a region known not to overlap with another, otherwise use AddRegion. |
| 194 | // returns whether the region was inserted. |
| 195 | bool AddNonOverlappingRegion(CacheRegion region); |
| 196 | |
| 197 | public: |
| 198 | SharedCache() = default; |
| 199 | explicit SharedCache(uint64_t addressSize); |
| 200 | |
| 201 | SharedCache(const SharedCache &) = delete; |
| 202 | SharedCache &operator=(const SharedCache &) = delete; |
| 203 | |
| 204 | SharedCache(SharedCache &&) noexcept = default; |
| 205 | SharedCache &operator=(SharedCache &&) noexcept = default; |
| 206 | |
| 207 | uint64_t GetBaseAddress() const { return m_baseAddress; } |
| 208 | std::shared_ptr<VirtualMemory> GetVirtualMemory() const { return m_vm; } |
| 209 | const std::vector<CacheEntry>& GetEntries() const { return m_entries; } |
| 210 | const AddressRangeMap<CacheRegion>& GetRegions() const { return m_regions; } |
| 211 | const std::unordered_map<uint64_t, CacheImage>& GetImages() const { return m_images; } |
| 212 | const std::unordered_map<uint64_t, CacheSymbol>& GetSymbols() const { return m_symbols; } |
| 213 | |
| 214 | void AddImage(CacheImage&& image); |
| 215 | |
| 216 | // Add a region that may overlap with another. |
| 217 | void AddRegion(CacheRegion&& region); |
| 218 | |
| 219 | void AddSymbol(CacheSymbol symbol); |
| 220 | |
| 221 | void AddSymbols(std::vector<CacheSymbol>&& symbols); |
| 222 | |
| 223 | // Adds the cache entry and populates the virtual memory using the mapping information. |
| 224 | // After being added the entry is read only, there is nothing that can modify it. |
| 225 | void AddEntry(CacheEntry entry); |
| 226 | |
| 227 | void ProcessEntryImages(const CacheEntry& entry); |
| 228 |