| 192 | } |
| 193 | |
| 194 | bool SharedCacheController::ApplyImage(BinaryView& view, const CacheImage& image) |
| 195 | { |
| 196 | // Load all regions of an image and mark the image as loaded. |
| 197 | // NOTE: The regions lock m_loadMutex themselves, so we do not hold it up here. |
| 198 | bool loadedRegion = false; |
| 199 | for (const auto& regionStart : image.regionStarts) |
| 200 | if (ApplyRegionAtAddress(view, regionStart)) |
| 201 | loadedRegion = true; |
| 202 | |
| 203 | // The ApplyRegionAtAddress no longer holds the lock, we can take it now. |
| 204 | std::unique_lock<std::shared_mutex> lock(m_loadMutex); |
| 205 | // If there was no loaded regions than we just want to forgo loading the image. |
| 206 | // We also skip if we already loaded the image itself. We do this after loading regions |
| 207 | // as we regions have their own check. |
| 208 | if (!loadedRegion || m_loadedImages.find(image.headerAddress) != m_loadedImages.end()) |
| 209 | return false; |
| 210 | |
| 211 | if (image.header) |
| 212 | { |
| 213 | // Header information is applied to the view here, such as sections. |
| 214 | auto machoProcessor = SharedCacheMachOProcessor(&view, m_cache.GetVirtualMemory()); |
| 215 | |
| 216 | // Adding a user section will mark all functions for updates unless we disable this. |
| 217 | // Because images are known separate compilation units, we have a real reason to make sure we don't mark all previously |
| 218 | // analyzed functions as updated. |
| 219 | auto prevDisabledState = view.GetFunctionAnalysisUpdateDisabled(); |
| 220 | view.SetFunctionAnalysisUpdateDisabled(true); |
| 221 | machoProcessor.ApplyHeader(GetCache(), *image.header); |
| 222 | view.SetFunctionAnalysisUpdateDisabled(prevDisabledState); |
| 223 | |
| 224 | // Load objective-c information. |
| 225 | auto objcProcessor = DSCObjC::SharedCacheObjCProcessor(&view, false, image.headerAddress); |
| 226 | try |
| 227 | { |
| 228 | if (m_processObjC) |
| 229 | objcProcessor.ProcessObjCData(); |
| 230 | if (m_processCFStrings) |
| 231 | objcProcessor.ProcessCFStrings(); |
| 232 | } |
| 233 | catch (std::exception& e) |
| 234 | { |
| 235 | // Let the user know there was an error in processing the objc stuff but let the image load |
| 236 | // regardless, as its non-critical. |
| 237 | m_logger->LogError("Failed to process ObjC information: %s", e.what()); |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | m_loadedImages.insert(image.headerAddress); |
| 242 | |
| 243 | m_logger->LogInfoF("Loaded image: '{}'", image.path); |
| 244 | |
| 245 | // TODO: This needs to be done in a "database save" callback. |
| 246 | // NOTE: We store on the parent view because hilariously, the view metadata is not available in view init. |
| 247 | view.GetParentView()->StoreMetadata(METADATA_KEY, GetMetadata()); |
| 248 | |
| 249 | // TODO: Partial failure state (i.e. 2 regions loaded, one failed) |
| 250 | return true; |
| 251 | } |
no test coverage detected