public static AddressTable getEntry(Program program, Address topAddr, TaskMonitor monitor,
			boolean checkExisting, int minimumTableSize, int alignment, int skipAmount,
			long minAddressOffset, boolean useShiftedAddressesIfNecessary, boolean checkForIndex,
			boolean useRelocationTable) {
		Memory memory = program.getMemory();
		Listing listing = program.getListing();

		int addressShiftAmount;
		boolean shiftedAddresses;
		if (useShiftedAddressesIfNecessary) {
			addressShiftAmount =
				program.getDataTypeManager().getDataOrganization().getPointerShift();
			shiftedAddresses = addressShiftAmount != 0;
		}
		else {
			shiftedAddresses = false;
			addressShiftAmount = 0;
		}

// TODO: need to specify the size of ptrs in this processor....

		// if the address doesn't start on the processors instruction alignment
		//   it shouldn't be the start of a table
		int langAlignment = program.getLanguage().getInstructionAlignment();
		if (alignment < 1 && langAlignment != 1) {
			alignment = langAlignment;
		}
		if (alignment < 1 || alignment > 8) {
			alignment = 1;
		}
		if (topAddr.getOffset() % alignment != 0) {
			return null;
		}

		AddressRange range = memory.getRangeContaining(topAddr);
		if (range == null) {
			return null;
		}

		ArrayList<Address> arrayElements = new ArrayList<>();
		HashSet<Address> arrayEntries = new HashSet<>();

		int count = 0;
		Address currentAddr = topAddr;
		int addrSize = program.getDefaultPointerSize();

		AddressSet pointerSet = new AddressSet();  // set where address pointers are - minus skipAmount

		while (!monitor.isCancelled() && range.contains(currentAddr)) {
			try {
				// get the value in address form of the bytes at address a
				long addrLong = 0;
				//For the 24 bit programs we see now, they all have a 00 pad after the 3 byte addr
				// so we have to treat the searched addrs as 4 byte, when they are created, they are 3 byte
				if (addrSize == 3) {
					int addrInt = memory.getInt(currentAddr);
					addrLong = addrInt & 0xffffffffL;
				}
				if (addrSize == 4) {
					int addrInt = memory.getInt(currentAddr);
					if (shiftedAddresses) {
						addrLong = ((addrInt << addressShiftAmount) & 0xffffffffL);
					}
					else {
						addrLong = addrInt & 0xffffffffL;
					}

				}
				else if (addrSize == 8) {
					addrLong = memory.getLong(currentAddr);
				}
				Address testAddr = currentAddr.getNewAddress(addrLong);

				if (testAddr.equals(Address.NO_ADDRESS)) {
					break;
				}

				// if this shouldn't be considered an address because it is too low in memory!
				if (addrLong > 0 && addrLong < minAddressOffset) {
					break;
				}

				// test that the value isn't 0
				//    May be bad if an address table has a 0 in it, but normally
				//    0 is not found in memory anyway, so better to be conservative
				if (addrLong == 0) {
					break;
				}

				// if the address isn't valid for this processors alignment
				if (testAddr.getOffset() % alignment != 0) {
					break;
				}

				// See if the tested address is contained in memory
				if (!memory.contains(testAddr)) {
					break;
				}

				// If the program is relocatable, and this address is not one of the relocations
				//   can't be a pointer
				if (useRelocationTable && !isValidRelocationAddress(program, currentAddr)) {
					break;
				}

				// if there is a ref in the middle of the table, then isn't a table, stops here...
				if (count > 1 &&
					program.getReferenceManager().getReferenceCountTo(currentAddr) > 0) {
					break;
				}

				// also check what the address pointer points to, if the thing
				//   existing there doesn't jibe with the pointer, don't do it.
				if (checkExisting && checkForCollisionAtTarget(program, testAddr)) {
					break;
				}

				// add the valid address to the list and increment past it
				arrayElements.add(testAddr);
				arrayEntries.add(currentAddr);
				pointerSet.add(currentAddr, currentAddr.add(addrSize - 1));
				currentAddr = currentAddr.add(addrSize + skipAmount);

				count++;
			}
			catch (MemoryAccessException e) {
				break;
			}
			catch (AddressOutOfBoundsException e) {
				break;
			}
		}

		// if table too small, don't even check later...
		if (count < minimumTableSize) {
			return null;
		}

		// Any reference or symbol breaks the address table.

		// Find the next reference after this address and adjust the table size
		//  if needed.
		Address nextSymAddr = null;
		try {
			AddressIterator addrIter =
				program.getReferenceManager().getReferenceDestinationIterator(topAddr.add(1), true);
			nextSymAddr = addrIter.next();
		}
		catch (AddressOutOfBoundsException e) {
			// ignore, no nextSymAddr
		}

		// Find the next symbol after this address and adjust the table size
		//  if needed.
		Address endAddr = topAddr.add((count * (addrSize + skipAmount)));
		if (nextSymAddr != null && nextSymAddr.compareTo(endAddr) < 0) {
			count = (int) (nextSymAddr.subtract(topAddr) / (addrSize + skipAmount));
		}
		if (count < minimumTableSize) {
			return null;
		}

		// iterate over defined codeunits in pointerSet
		if (checkExisting) {
			CodeUnit codeUnitContaining = listing.getCodeUnitContaining(topAddr);
			if (codeUnitContaining != null) {
				if (!codeUnitContaining.getMinAddress().equals(topAddr)) {
					return null;
				}
				// if instruction at topAddr, then this not a good table, data is OK
				if (codeUnitContaining instanceof Instruction) {
					return null;
				}
			}

			// get next instruction, restrict table to before instruction
			Instruction instructionAfter = listing.getInstructionAfter(topAddr);
			endAddr = topAddr.add((count * (addrSize + skipAmount)));
			if (instructionAfter != null) {
				Address iAddr = instructionAfter.getMinAddress();
				if (iAddr.compareTo(endAddr) < 0) {
					count = (int) (iAddr.subtract(topAddr) / (addrSize + skipAmount));
				}
			}
			if (count < minimumTableSize) {
				return null;
			}

			// look for defined data that isn't already a pointer that doesn't align with
			//  the tables pointer starts
			endAddr = topAddr.add((count * (addrSize + skipAmount)) - 1);
			DataIterator definedData = listing.getDefinedData(topAddr, true);
			while (definedData.hasNext()) {
				Data data = definedData.next();
				// no data found or past end of table
				Address dataAddr = data.getMinAddress();
				if (dataAddr.compareTo(endAddr) > 0) {
					break;
				}
				// data found at start of pointer
				if (arrayEntries.contains(dataAddr)) {
					// if pointer, OK
					if (data.isPointer()) {
						continue;
					}
				}

				// undefined data is OK, could be a pointer
				if (data.getDataType() instanceof Undefined) {
					continue;
				}

				// data intersects, calculate valid entries and stop looking
				if (pointerSet.intersects(dataAddr, data.getMaxAddress())) {
					count = (int) (dataAddr.subtract(topAddr) / (addrSize + skipAmount));
					break;
				}
			}

		}

		if (count < minimumTableSize) {
			return null;
		}

		currentAddr = topAddr.add(count * (addrSize + skipAmount));

		Address[] tableElements = new Address[count];
		arrayElements.subList(0, count).toArray(tableElements);
		arrayElements = null;
		// Warning: arrayElements is no longer valid after this!

		// Don't check if the table is too large
		// TODO: This is not statistically correct.
		//       Only small tables should be found, and the probability that a run of
		//       random bytes after a table should be set to some large number.
		//       Fix for now by not searching, unless in address table searcher.
		if (checkForIndex && count < 128) {
			// figure out the address immediately after the table
			Address topIndexAddr = currentAddr;
			// check for tableElement that is closest to the bottom of the address table
			// to determine the max size of the index array
			long maxIndexSize = 100000;
			for (Address tableElement : tableElements) {
				long temp = tableElement.subtract(topIndexAddr);
				// this is the case where at least one of the elements is before the table
				// make temp the size of the rest of the memory segment - if it is larger than the
				// current maxIndexSize it will get overwritten in the next if statement
				if (temp < 0) {
					MemoryBlock block = memory.getBlock(topIndexAddr);
					if (block == null) {
						temp = 0;
					}
					else {
						temp = block.getEnd().subtract(topIndexAddr);
					}
				}
				if (temp < maxIndexSize) {
					maxIndexSize = temp;
				}
			}

			//search for index after the table
			int numIndexBytes = 0;
			int numZeroBytes = 0;

			boolean isIndex = true;
			if (maxIndexSize == 0) {
				isIndex = false;
			}

			while ((isIndex) && (numIndexBytes < maxIndexSize)) {
				byte b;
				try {
					b = memory.getByte(currentAddr);
				}
				catch (MemoryAccessException e) {
					break;
				}

				if ((b >= 0) && (b < count)) {
					numIndexBytes++;
					if (b == 0) {
						numZeroBytes++;
					}
				}
				else {
					isIndex = false;
				}
				currentAddr = currentAddr.next();
			}
			// I added the check for no more than 100 zeros for the cases where there are huge runs of zeros
			// followed by a valid index value - not sure if 100 is to big or too small
			if ((numIndexBytes >= count) && (numZeroBytes < numIndexBytes) &&
				(numZeroBytes < 100)) {
				return new AddressTable(topAddr, tableElements, topIndexAddr, numIndexBytes,
					addrSize, skipAmount, shiftedAddresses);
			}
		}
		return new AddressTable(topAddr, tableElements, null, 0, addrSize, skipAmount,
			shiftedAddresses);
	}
Get an Address Table Object (allows you to specify whether to use shifted
addresses or not)

@param program
@param topAddr starting adddress of the table
@param checkExisting check for existing instructions, data, or labels
@param minimumTableSize minimum table size
@param alignment only return a table for addresses that fall on alignment
           in bytes
@param skipAmount number of bytes to skip between address entries
@param minAddressOffset minimum value to be considered a pointer,
           dangerous to go below 1024 for some things
@param checkForIndex true if check for a single byte index table after
           the address table
@param useRelocationTable true to only consider pointers that are in the
           relocationTable for relocatable programs
@return null if no valid table exists at the topAddr
Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AddressTable.java