private void recoverSwitches(final Program program, AddressSet destSet,
			SymbolicPropogator symEval, TaskMonitor monitor) throws CancelledException {

		// now handle symbolic execution assuming values!
		class SwitchEvaluator implements ContextEvaluator {

			int tableSizeMax = 64;
			Long assumeValue = Long.valueOf(0);
			Address targetSwitchAddr = null;
			int addrByteSize = 1;
			boolean hitTheGuard = false;
			ArrayList<Address> targetList = new ArrayList<Address>();
			ArrayList<Address> accessList = new ArrayList<Address>();

			public void init(Address loc, int maxSize) {
				addrByteSize = 1;
				assumeValue = Long.valueOf(0);
				tableSizeMax = maxSize;
				targetSwitchAddr = loc;
				hitTheGuard = false;

				targetList.clear();
				accessList.clear();
			}

			public void initForCase(Long assume) {
				assumeValue = Long.valueOf(assume);
				hitTheGuard = false;
			}

			public int getTableSizeMax() {
				return tableSizeMax;
			}

			public int getAddrByteSize() {
				return addrByteSize;
			}

			public ArrayList<Address> getTargetList() {
				return targetList;
			}

			@Override
			public boolean evaluateContextBefore(VarnodeContext context, Instruction instr) {
				return false;
			}

			@Override
			public boolean evaluateContext(VarnodeContext context, Instruction instr) {
				if (context.readExecutableCode()) {
					return true;
				}
				// find the cmpli to set the size of the table
				//    tableSize = size
				String mnemonic = instr.getMnemonicString();
				if ((mnemonic.compareToIgnoreCase("cmp") == 0)) {
					int numOps = instr.getNumOperands();
					if (numOps > 1) {
						Register reg = instr.getRegister(numOps - 2);
						if ((reg != null)) {
							context.clearRegister(reg);
							Scalar scalar = instr.getScalar(numOps - 1);
							if (scalar != null) {
								int newTableSizeMax = (int) scalar.getSignedValue() + 2;
								if (newTableSizeMax > 0 && newTableSizeMax < 128) {
									tableSizeMax = newTableSizeMax;
								}
//								RegisterValue rval = context.getRegisterValue(reg);
//								if (rval != null) {
//									long lval = rval.getSignedValue().longValue();
//									if (lval < 0)
//										tableIndexOffset = -lval;
//								} else {
//								}
							}
						}
					}
					hitTheGuard = true;
				}
				if ((mnemonic.compareToIgnoreCase("sub") == 0)) {
					int numOps = instr.getNumOperands();
					if (numOps > 1) {
						Register reg = instr.getRegister(numOps - 2);
						if ((reg != null)) {
							BigInteger val = context.getValue(reg, true);
							if (val == null) {
								return false;
							}
							context.clearRegister(reg);
							Scalar scalar = instr.getScalar(numOps - 1);
							if (scalar == null) {
								return false;
							}
							context.setValue(reg,
								val.add(BigInteger.valueOf(scalar.getSignedValue())));
							val = context.getValue(reg, true);
//							if (scalar != null) {
//								tableSizeMax = (int) scalar.getSignedValue() + 1;
//								RegisterValue rval = context.getRegisterValue(reg);
//								if (rval != null) {
//									long lval = rval.getSignedValue().longValue();
//									if (lval < 0)
//										tableIndexOffset = -lval;
//								} else {
//								}
//							}
						}
					}
//					hitTheGuard = true;
				}
				return false;
			}

			@Override
			public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop,
					Address constant, int size, DataType dataType, RefType refType) {
				return null;
			}

			@Override
			public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
					Address address, int size, DataType dataType, RefType refType) {

				// if ever see a reference to 0, something went wrong, stop the process
				if (address == null) {
					return terminatePropogation(context);
				}

				// for switches, if access is below 256, then there is a problem
				// if ever loading from instructions in memory, must EXIT!
				//
				long offset = address.getOffset();
				if ((offset >= 0 && offset < 256) || context.readExecutableCode()) {
					return terminatePropogation(context);
				}
				if (!((refType.isComputed() || refType.isConditional() == !followConditional) &&
					program.getMemory().contains(address))) {
					if (refType.isRead()) {
						if (targetList.contains(address)) {
							return terminatePropogation(context);
						}
						size = createDataType(instr, address);
						if (size != 0) {
							addrByteSize = size;
						}
					}
					return false;
				}
				if (refType.isJump() || refType.isCall()) {
					if (accessList.contains(address)) {
						return terminatePropogation(context);
					}
					long diff = Math.abs(address.subtract(targetSwitchAddr));
					// don't allow jumps backward, or too far if this is not a call
					if (refType.isCall() || diff < 32 * 1024) {
						address = flowArmThumb(program, instr, context, address,
							instr.getFlowType(), false);
						if (address != null) {
							targetList.add(address);
						}
					}
					return false;
				}
				// no markup, computing the jump table
				return false;
			}

			private boolean terminatePropogation(VarnodeContext context) {
				hitTheGuard = false;
				context.setReadExecutableCode();
				return false;
			}

			@Override
			public boolean evaluateDestination(VarnodeContext context, Instruction instruction) {
				return instruction.getMinAddress().equals(targetSwitchAddr);
			}
			
			@Override
			public boolean evaluateReturn(Varnode retVN, VarnodeContext context, Instruction instruction) {
				return false;
			}
			
			@Override
			public Long unknownValue(VarnodeContext context, Instruction instruction,
					Varnode node) {
				if (node.isRegister()) {
					Register reg = program.getRegister(node.getAddress());
					if (reg != null) {
						// never assume for flags, or control registers
						String regName = reg.getName();
						if (regName.equals("sp")) {
							return null;
						}
						if (!regName.startsWith("r")) {
							return Long.valueOf(0);
						}
					}
					if (hitTheGuard) {
						return assumeValue;
					}
				}
				if (hitTheGuard && context.isSymbol(node)) {
					return assumeValue;
				}
				return null;
			}

			@Override
			public boolean followFalseConditionalBranches() {
				return false;
			}

			@Override
			public boolean evaluateSymbolicReference(VarnodeContext context, Instruction instr,
					Address address) {
				return false;
			}

			@Override
			public boolean allowAccess(VarnodeContext context, Address addr) {
				accessList.add(addr);
				return false;
			}
		}

		SwitchEvaluator switchEvaluator = new SwitchEvaluator();

		// now flow with the simple block of this branch....

		// for each unknown branch destination,
		AddressIterator iter = destSet.getAddresses(true);
		SimpleBlockModel model = new SimpleBlockModel(program);
		while (iter.hasNext() && !monitor.isCancelled()) {
			Address loc = iter.next();
			CodeBlock bl = null;
			try {
				bl = model.getFirstCodeBlockContaining(loc, monitor);
			}
			catch (CancelledException e) {
				break;
			}
			AddressSet branchSet = new AddressSet(bl);
			CodeBlockReferenceIterator bliter;
			try {
				bliter = bl.getSources(monitor);
				while (bliter.hasNext()) {
					if (hasCallsTo(program, bl)) {
						break;
					}
					CodeBlockReference sbl = bliter.next();
					bl = sbl.getSourceBlock();
					if (bl == null) {
						continue;
					}
					if (!sbl.getFlowType().isCall()) {
						branchSet.add(bl);
					}
					if (sbl.getFlowType().isJump() && bl.getNumSources(monitor) == 1) {
						if (sbl.getFlowType().isConditional()) {
							followConditional = true;
							break;
						}
						bliter = bl.getSources(monitor);
					}
				}
			}
			catch (CancelledException e) {
				break;
			}

			switchEvaluator.init(loc, 64);

			Instruction targetInstr = program.getListing().getInstructionAt(loc);

			SymbolicPropogator targetEval = symEval;
			// if this is a tbX instruction, don't assume any old values
			if (targetInstr != null && targetInstr.getMnemonicString().startsWith("tb")) {
				targetEval = new SymbolicPropogator(program);
			}

			Address zeroAddr = targetInstr.getMinAddress().getNewAddress(0);
			for (long assume = 0; assume < switchEvaluator.getTableSizeMax(); assume++) {
				switchEvaluator.initForCase(Long.valueOf(assume));

				targetEval.flowConstants(branchSet.getMinAddress(), branchSet, switchEvaluator,
					false, monitor);
				// go around once, table might be 1 based
				if (assume > 0 && targetEval.readExecutable()) {
					break;
				}
				// if it didn't get it after try with 1
				if (assume > 1 && switchEvaluator.getTargetList().size() < 1) {
					break;
				}
				// if the target list ever contains zero, is bad
				if (switchEvaluator.getTargetList().contains(zeroAddr)) {
					switchEvaluator.getTargetList().clear();
					break;
				}
			}

			// re-create the function body with the newly found code
			if (switchEvaluator.getTargetList().size() > 1) {
				Iterator<Address> liter = switchEvaluator.getTargetList().iterator();
				Address firstAddress = switchEvaluator.getTargetList().get(0);
				while (liter.hasNext()) {
					if (!firstAddress.equals(liter.next())) {
						AddressTable table;
						table = new AddressTable(loc,
							switchEvaluator.getTargetList().toArray(new Address[0]),
							switchEvaluator.getAddrByteSize(), 0, false);
						Instruction jmpInstr = program.getListing().getInstructionAt(loc);
						if (jmpInstr.getReferencesFrom().length <= 1) {
							Iterator<Address> jmpIter = switchEvaluator.getTargetList().iterator();
							while (jmpIter.hasNext()) {
								Address address = jmpIter.next();
								jmpInstr.addMnemonicReference(address, jmpInstr.getFlowType(),
									SourceType.ANALYSIS);
							}
						}
						table.disassemble(program, jmpInstr, monitor);
						table.fixupFunctionBody(program, jmpInstr, monitor);
						labelTable(program, loc, switchEvaluator.getTargetList());
						switchEvaluator.getTargetList().clear();
						break;
					}
				}
			}
			if (switchEvaluator.getTargetList().size() > 0) {
				AddressTable table;
				table = new AddressTable(loc, switchEvaluator.getTargetList().toArray(new Address[0]),
						switchEvaluator.getAddrByteSize(), 0, false);
				table.disassemble(program, targetInstr,monitor);
			}
		}
	}
Check if there are any data references to this location.
@param program
@param addr
@return true if there are any data references to addr
Ghidra/Processors/ARM/src/main/java/ghidra/app/plugin/core/analysis/ArmAnalyzer.java