public Varnode getValue(Varnode varnode, boolean signed, ContextEvaluator evaluator) {
		if (varnode == null) {
			return null;
		}
		// for constant, return the constant value
		if (isConstant(varnode)) {
			return varnode;
		}
		Varnode rvnode = null;
		if (varnode.isUnique()) {
			rvnode = getMemoryValue(tempUniqueVals,varnode,signed);
			if (rvnode == null && keepTempUniqueValues) {
				rvnode = getMemoryValue(uniqueVals,0,varnode,signed);
			}
		}
		else {
			rvnode = getMemoryValue(tempVals, varnode, signed);
		}
		if (rvnode != null) {
			if (debug) {
				Msg.info(this, "     Tmp " + varnode + "  =  " + rvnode);
			}
			if (rvnode.getAddress().equals(BAD_ADDRESS)) {
				return null;
			}
			return rvnode;
		}

		if (isRegister(varnode)) {
			Varnode value = getMemoryValue(this.regVals, 0, varnode, signed);
			if (value != null) {
				int spaceVal = value.getSpace();

				if (value.isConstant()) {
					long lvalue = value.getOffset();
					int size = value.getSize();

					// -1 and zero constants pulled from a register are suspect
					if ((value.getOffset() == -1 || value.getOffset() == 0)) {
						spaceVal = SUSPECT_OFFSET_SPACEID;
						value = createVarnode(lvalue, spaceVal, size);
					}
					else if (signed) {
						lvalue = (lvalue << 8 * (8 - size)) >> 8 * (8 - size);
						value = createVarnode(lvalue, spaceVal, size);
					}
				}
				rvnode = value;

				if (debug) {
					Register reg = trans.getRegister(varnode);
					String name = (reg != null ? reg.getName() : varnode.toString());
					Msg.info(this, "  " + name + " = " + print(rvnode));
				}

				// value is bad, just return original, someone else will deal with it
				if (!rvnode.getAddress().equals(BAD_ADDRESS)) {
					return rvnode;
				}
			}

			return varnode;   // just return the register then, someone else will deal with it...
		}

		boolean isAddr = varnode.isAddress();
		boolean isSymbolicAddr = isSymbolicSpace(varnode.getSpace());
		if (isAddr || isSymbolicAddr) {
			// don't ever trust a load from memory location 0/-1 even if we wrote it, could be a null/flag
			// We can put references to that location, but don't trust values there even if we wrote them
			long varnodeOffset = varnode.getOffset();
			if (isAddr &&
				(varnodeOffset == 0 || varnodeOffset == 0xffffffff || varnodeOffset == -1L)) {
				return null;
			}

			// see if we wrote a value to memory here
			Varnode lvalue = getMemoryValue(varnode, signed);
			if (lvalue != null) {
				if (debug) {
					Msg.info(this, "   " + varnode + " = " + print(lvalue));
				}
				// if this is an offset reference, ONLY allow it to be offset into the stack, no other register offset.
				// can't count on the offset staying the same.
				if (isSymbolicAddr) {
					// don't allow a zero/-1 constant pulled from a symbolic space.
					if (isConstant(lvalue) &&
						(lvalue.getOffset() == 0 || lvalue.getOffset() == -1)) {
						return null;
					}
				}
				return lvalue;
			}

			// get the value from memory
			Address addr = varnode.getAddress();

			// if this reference belongs in this address space, must re-map it
			if (currentAddress.getAddressSpace().isOverlaySpace()) {
				addr = currentAddress.getAddressSpace().getOverlayAddress(addr);
			}

			if (isSymbolicAddr) {
				return null;
			}

			if (this.program.getListing().getInstructionContaining(addr) != null) {
				hitDest = true;
			}

			// don't trust any place that has an external reference off of it
			Reference[] refsFrom = program.getReferenceManager().getReferencesFrom(addr);
			if (refsFrom.length > 0 && refsFrom[0].isExternalReference()) {
				Address external = refsFrom[0].getToAddress();
				return createVarnode(external.getOffset(), external.getAddressSpace().getSpaceID(), 0);
			}

			// If the memory is Writeable, then maybe don't trust it
			boolean isReadOnly = isReadOnly(addr);
			if (!isReadOnly) {
				// don't try to see how far away if it is in a different space.
				if (addr.getAddressSpace()
						.equals(currentAddress.getAddressSpace())) {
					long diff = addr.subtract(currentAddress);
					// if the value loaded is too far away, ask the evaluator if it should be trusted.
					if (diff < 0 || diff > 4096) {
						if (evaluator != null && !evaluator.allowAccess(this, addr)) {
							return null;
						}
					}
				}
			}
			int size = varnode.getSize();
			try {
				long value = 0;
				switch (size) {
					case 1:
						value = this.program.getMemory().getByte(addr) & 0xff;
						break;
					case 2:
						value = this.program.getMemory().getShort(addr) & 0xffff;
						break;
					case 4:
						value = this.program.getMemory().getInt(addr) & 0xffffffff;
						break;
					case 8:
						value = this.program.getMemory().getLong(addr);
						break;
					default:
						return null;
				}

				// Don't trust zero values loaded out of memory, even if it is read-only memory.
				if (value == 0) {
					return null;
				}

				if (signed) {
					value = (value << 8 * (8 - size)) >> 8 * (8 - size);
				}

				// constants pulled from memory are suspect
				// unless memory is readonly, or given access from evaluator (trustWriteAccess)
				int spaceId = SUSPECT_OFFSET_SPACEID;
				if (isReadOnly || (evaluator != null && evaluator.allowAccess(this, addr))) {
					spaceId = 0;
				}
				return createVarnode(value, spaceId, size);

			}
			catch (MemoryAccessException e) {
				// Don't care
			}
		}

		// is there an assumed value that should be returned for any unknown value?
		if (evaluator != null && !varnode.isAddress()) {
			Instruction instr = getCurrentInstruction(currentAddress);
			Long lval = evaluator.unknownValue(this, instr, varnode);
			if (lval == null && !varnode.isUnique()) {
				return varnode;
			}
		}
		return null;
	}
@return Register that represents the stack register
Ghidra/Features/Base/src/main/java/ghidra/program/util/VarnodeContext.java