private boolean analyzeFunction(Program program, Address entry, TaskMonitor monitor)
			throws CancelledException {
		Listing listing = program.getListing();
		Function f = listing.getFunctionAt(entry);
		if (f == null) {
			return false;
		}
		int depthChange = 0;

		// Perform depth search of all functions reached by this function.
		// Any function that has not had its stack analyzed is added to a list.
		// This way, the lowest level functions frames are looked at to try and determine their
		//  stack purge, before this functions stack is analyzed.
		Stack<Function> stack = new Stack<Function>(); // functions needing to be looked at for valid frames
		ArrayList<Function> funcList = new ArrayList<Function>(); // list of functions needing stack frames created
		stack.push(f);
		while (!stack.isEmpty()) {
			monitor.checkCancelled();
			Function func = stack.pop();
			// if the purge for the function is unknown, it has not been looked at yet.
			//  we need to add it to the list to analyze its stack frame.
			if (func.getStackPurgeSize() == Function.UNKNOWN_STACK_DEPTH_CHANGE) {
				// look at any call references out of this function and put them on
				//   the stack to be looked at
				AddressIterator iter =
					program.getReferenceManager().getReferenceSourceIterator(func.getBody(), true);
				while (iter.hasNext()) {
					monitor.checkCancelled();
					Address fromAddr = iter.next();
					Reference refs[] =
						program.getReferenceManager().getFlowReferencesFrom(fromAddr);
					for (Reference ref : refs) {
						if (ref.getReferenceType().isCall()) {
							Address calledAddr = ref.getToAddress();
							Function destFunc = program.getListing().getFunctionAt(calledAddr);
							if (destFunc != null && !destFunc.isInline()) {
								stack.push(destFunc);
							}
						}
					}
				}

				// This function needs its stack looked at.
				//   Set its stack purge to invalid, so won't be added to list again if called recursively.
				func.setStackPurgeSize(Function.INVALID_STACK_DEPTH_CHANGE);
				funcList.add(0, func);
			}
			else if (forceProcessing && func.getEntryPoint().equals(entry)) {
				// This function needs its stack looked at.
				//   Set its stack purge to invalid, so won't be added to list again if called recursively.
				func.setStackPurgeSize(Function.INVALID_STACK_DEPTH_CHANGE);
				funcList.add(0, func);
			}
		}

		// Process all the functions identified as needing stack analysis.
		// The list will have the lowest level functions analyzed first.
		PrototypeModel defaultModel = program.getCompilerSpec().getDefaultCallingConvention();
		int default_extraPop = defaultModel.getExtrapop();
		int default_stackshift = defaultModel.getStackshift();

		while (!funcList.isEmpty()) {
			monitor.checkCancelled();
			Function func = funcList.remove(0);
			monitor.setMessage("Stack " + func.getName());

			depthChange = createStackPointerVariables(func, monitor);

			PrototypeModel callingConvention = func.getCallingConvention();

			int stackShift = default_stackshift;
			int extraPop = default_extraPop;
			if (callingConvention != null) {
				stackShift = callingConvention.getStackshift();
				extraPop = callingConvention.getExtrapop();
			}

			if (depthChange > 0xfffff || depthChange < -0xfffff) {
				depthChange = Function.INVALID_STACK_DEPTH_CHANGE;
			}

			// Stack purge is defined as the number of extra bytes that are popped
			//   off of the stack beyond the normal calling conventions.
			//   the default_callstackmod includes the normal call stack shift,
			//   so subtract it out.
			if (extraPop != PrototypeModel.UNKNOWN_EXTRAPOP) {
				depthChange = extraPop - stackShift;
			}
			else if (depthChange != Function.INVALID_STACK_DEPTH_CHANGE) {
				depthChange -= stackShift;
			}
			func.setStackPurgeSize(depthChange);
		}
		return true;
	}
Analyze a function to build a stack frame based on stack references.

@param entry   The address of the entry point for the new function
@param monitor the task monitor that is checked to see if the command has
been cancelled.
@throws CancelledException if the user canceled this command
Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionResultStateStackAnalysisCmd.java