@Override
	public DynamicTableColumn<RegisterRow, ?, ?> create() {
		return new AbstractDynamicTableColumn<RegisterRow, String, Void>() {
			@Override
			public String getColumnName() {
				return COL_NAME;
			}

			@Override
			public String getValue(RegisterRow rowObject, Settings settings, Void dataSource,
					ServiceProvider serviceProvider) throws IllegalArgumentException {
				DebuggerCoordinates current = rowObject.getCurrent();
				Trace trace = current.getTrace();
				if (trace == null) {
					return "";
				}

				TracePropertyMap<String> taintMap = current.getTrace()
						.getAddressPropertyManager()
						.getPropertyMap(PROP_NAME, String.class);

				if (taintMap == null) {
					return "";
				}

				Register register = rowObject.getRegister();
				TracePropertyMapSpace<String> taintSpace;
				AddressSpace addressSpace = register.getAddressSpace();
				if (addressSpace.isRegisterSpace()) {
					taintSpace = taintMap.getPropertyMapRegisterSpace(current.getThread(),
						current.getFrame(), false);
				}
				else {
					taintSpace = taintMap.getPropertyMapSpace(addressSpace, false);
				}
				if (taintSpace == null) {
					return "";
				}

				// Cheat the deserialization/reserialization here
				StringBuffer vec = new StringBuffer();
				int count = register.getNumBytes();
				Address start = register.getAddress();
				for (int i = 0; i < count; i++) {
					vec.append('[');
					String taint = taintSpace.get(current.getViewSnap(), start.addWrap(i));
					vec.append(taint == null ? "" : taint);
					vec.append(']');
				}
				return vec.toString();
			}
		};
	}
A factory for the "Taint" column in the "Registers" panel

<p>
For the most part, this is just a matter of accessing the property map and rendering the value on
screen.
Ghidra/Debug/TaintAnalysis/src/main/java/ghidra/taint/gui/field/TaintDebuggerRegisterColumnFactory.java