@Override
	public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
			throws CancelledException {

		// Get the memory blocks to search for exception handling structures.
		List<MemoryBlock> ehBlocks =
			ProgramMemoryUtil.getMemoryBlocksStartingWithName(program, set, ".rdata", monitor);
		if (ehBlocks.isEmpty()) {
			ehBlocks =
				ProgramMemoryUtil.getMemoryBlocksStartingWithName(program, set, ".text", monitor);
		}

		// search for FuncInfo data type's magic number pattern.
		String lePattern =
			"[\\x20,\\x21,\\x22]\\x05\\x93[\\x19,\\x39,\\x59,\\x79,\\x99,\\xb9,\\xd9,\\xf9]";
		String bePattern =
			"[\\x19,\\x39,\\x59,\\x79,\\x99,\\xb9,\\xd9,\\xf9]\\x93\\x05[\\x20,\\x21,\\x22]";

		String pattern = program.getLanguage().isBigEndian() ? bePattern : lePattern;
		int alignment = 4;

		SearchSettings settings = new SearchSettings().withAlignment(alignment);
		settings = settings.withIncludeInstructions(false); 	// only search data

		ByteMatcher matcher = new RegExByteMatcher(pattern, settings);
		AddressableByteSource byteSource = new ProgramByteSource(program);
		Memory memory = program.getMemory();
		AddressSet addresses = memory.getLoadedAndInitializedAddressSet().intersect(set);

		// Only want to search exception handling memory blocks.
		addresses = getAddressSet(ehBlocks).intersect(addresses);

		MemorySearcher searcher = new MemorySearcher(byteSource, matcher, addresses, MATCH_LIMIT);

		ListAccumulator<MemoryMatch> accumulator = new ListAccumulator<>();
		searcher.findAll(accumulator, monitor);
		List<MemoryMatch> results = accumulator.asList();

		// Establish the options to use when creating the exception handling data.
		// For now these are fixed. Later these may need to come from analysis options.
		DataValidationOptions validationOptions = new DataValidationOptions();
		DataApplyOptions applyOptions = new DataApplyOptions();

		monitor.setMaximum(results.size());

		// Attempt to create data at each address if it appears to be valid for the data type.
		int count = 0;
		for (MemoryMatch match : results) {

			monitor.setProgress(count++);
			if (monitor.isCancelled()) {
				return false;
			}

			Address address = match.getAddress();
			if (address.getOffset() % alignment != 0) {
				continue; // Skip non-aligned addresses.
			}
			// Validate the possible FuncInfo before trying to create it.
			EHFunctionInfoModel model =
				new EHFunctionInfoModel(program, address, validationOptions);
			try {
				model.validate();
				model.validateCounts(MAX_MAP_ENTRY_COUNT);
				model.validateLocationsInSameBlock();

				// Create FuncInfo data at the address of the magic number, if the data appears valid.
				// This can also create associated exception handling data based on the options.
				Command<Program> cmd =
					new CreateEHFuncInfoBackgroundCmd(address, validationOptions, applyOptions);
				cmd.applyTo(program);
			}
			catch (InvalidDataTypeException e) {
				// Doesn't appear valid so just move on to the next one.
				// This doesn't log an error because we are trying to find valid exception
				// handling structures and apply them.
			}
		}

		return true;
	}
Creates an analyzer for determining PE exception handling data.
Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/plugin/prototype/MicrosoftCodeAnalyzerPlugin/PEExceptionAnalyzer.java