protected void readControlBlock(boolean applyStruct)
			throws InvalidControlBlockException, CodeUnitInsertionException {

		if (applyStruct) {
			DataUtilities.createData(program, infoStructAddr, infoProgramStruct, -1,
				ClearDataMode.CLEAR_ALL_CONFLICT_DATA);
		}

		TerminatedStringDataType stringType =
			new TerminatedStringDataType(program.getDataTypeManager());

		Structure functionInfoStruct =
			(Structure) infoProgramStruct.getDataTypeManager().getDataType(CategoryPath.ROOT,
				"FunctionInfo");
		if (functionInfoStruct == null) {
			throw new AssertException("FunctionInfo structure not yet resolved");
		}

		int nameOffset = getStructureComponent(functionInfoStruct, "name");
		int funcOffset = getStructureComponent(functionInfoStruct, "func");
		int numTestOffset = getStructureComponent(functionInfoStruct, "numTest");

		try {

			DumbMemBufferImpl memBuffer =
				new DumbMemBufferImpl(program.getMemory(), infoStructAddr);
			int functionArrayPtrOffset =
				getStructureComponent(infoProgramStruct, "funcInfoArrayPtr");
			Address functionInfoAddress =
				readDataPointer(memBuffer, functionArrayPtrOffset, applyStruct);

			Msg.info(this, "Loading FunctionInfo array at " + functionInfoAddress);

			while (true) {
				// Read function table
				memBuffer.setPosition(functionInfoAddress);

				if (applyStruct) {
					DataUtilities.createData(program, functionInfoAddress, functionInfoStruct, -1,
						ClearDataMode.CLEAR_ALL_CONFLICT_DATA);
					forceCodePointer(functionInfoAddress.add(funcOffset));
				}

				Address funcNamePtr = readDataPointer(memBuffer, nameOffset, applyStruct);
				Address funcPtr = readCodePointer(memBuffer, funcOffset, applyStruct);
				int numTest = memBuffer.getInt(numTestOffset);

				if (funcNamePtr.getOffset() == 0) {
					break;
				}

				memBuffer.setPosition(funcNamePtr);
				String functionName =
					(String) stringType.getValue(memBuffer, SettingsImpl.NO_SETTINGS, 0);

				if (funcPtr.getOffset() != 0) {
					MemoryBlock block = program.getMemory().getBlock(funcPtr);
					if (block == null || !block.isInitialized()) {
						throw new InvalidControlBlockException(
							infoProgramStruct.getName() + " @ " + infoStructAddr.toString(true) +
								" has invalid pointer offset for function: " + functionName +
								" -> " + funcPtr);
					}
				}

				if (funcPtr.getOffset() != 0) {
					FunctionInfo info = new FunctionInfo(functionName, funcPtr, numTest);
					functions.add(info);
					functionMap.put(functionName, info);
				}

				functionInfoAddress = functionInfoAddress.add(functionInfoStruct.getLength());

			}

		}
		catch (MemoryAccessException e) {
			throw new InvalidControlBlockException(
				infoProgramStruct.getName() + " program read error", e);
		}

	}
Check for a Data pointer at the specified address and return the referenced
address.
@param addr address of stored pointer
@return pointer referenced address or null if no pointer found
Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestAbstractControlBlock.java