private void analyzeDyldCacheFunctionStarts(Program program, List<ByteProvider> providers,
			AddressSetView set, TaskMonitor monitor, MessageLog log)
			throws MachException, IOException, CancelledException {
		Map<DyldCacheHeader, ByteProvider> providerMap = new HashMap<>();

		// Parse all DYLD Cache headers.  There could be more that one if the DYLD Cache is "split".
		for (ByteProvider provider : providers) {
			DyldCacheHeader header = new DyldCacheHeader(new BinaryReader(provider, true));
			header.parseFromFile(false, log, monitor);
			providerMap.put(header, provider);
		}

		// Process each Mach-O header found in each DYLD Cache header
		for (DyldCacheHeader dyldCacheHeader : providerMap.keySet()) {
			List<DyldCacheImage> mappedImages = dyldCacheHeader.getMappedImages();
			monitor.initialize(mappedImages.size());
			for (DyldCacheImage mappedImage : mappedImages) {
				String name = new File(mappedImage.getPath()).getName();
				monitor.checkCancelled();
				monitor.setMessage("Analyzing function starts for " + name + "...");
				monitor.incrementProgress(1);

				// Parse Mach-O header
				MachHeader machoHeader = new MachHeader(providerMap.get(dyldCacheHeader),
					mappedImage.getAddress() - dyldCacheHeader.getBaseAddress(), false);
				machoHeader.parse();

				// The list of function starts should always be in a __LINKEDIT segment.
				// If the DYLD Cache is "split", a Mach-O's __LINKEDIT segment may live in a
				// different provider.
				SegmentCommand linkEdit = machoHeader.getSegment(SegmentNames.SEG_LINKEDIT);
				if (linkEdit != null) {
					boolean foundLinkEdit = false;
					for (DyldCacheHeader header : providerMap.keySet()) {
						for (DyldCacheMappingInfo mappingInfo : header.getMappingInfos()) {
							if (mappingInfo.contains(linkEdit.getVMaddress(), true)) {
								analyzeFunctionStarts(program, machoHeader, set, monitor);
								foundLinkEdit = true;
								break;
							}
						}
						if (foundLinkEdit) {
							break;
						}
					}
				}
				else {
					log.appendMsg(
						"Failed to find " + SegmentNames.SEG_LINKEDIT + " segment for " + name);
				}
			}
		}
	}
Finds and creates new functions in the given DyldCache using the LC_FUNCTION_STARTS load 
command from each Mach-O header

@param program The {@link Program}
@param providers A {@link List} of {@link ByteProvider}s that contains the original file 
  bytes
@param set The set of addresses to find new functions at
@param monitor A cancellable monitor
@param log The log
@throws MachException If there was an issue parsing the headers
@throws IOException If an IO-related issue occurred
@throws CancelledException If the user cancelled
Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/MachoFunctionStartsAnalyzer.java