private void mergeFunctionSymbol(Address fromEntryPoint, boolean replacePrimary,
			LongLongHashtable conflictSymbolIDMap, TaskMonitor monitor)
			throws DuplicateNameException, InvalidInputException {
		// Assumes: The function in the destination program should already be replaced at this point.
		FunctionManager fromFunctionMgr = fromProgram.getFunctionManager();
		FunctionManager toFunctionMgr = toProgram.getFunctionManager();
		Address toEntryPoint = originToResultTranslator.getAddress(fromEntryPoint);
		Function fromFunc = fromFunctionMgr.getFunctionAt(fromEntryPoint);
		Function toFunc = toFunctionMgr.getFunctionAt(toEntryPoint);
		SymbolTable toSymTab = toProgram.getSymbolTable();
		if (fromFunc != null) {
			Symbol fromSymbol = fromFunc.getSymbol();
			String fromName = fromSymbol.getName();
			boolean fromDefault = fromSymbol.getSource() == SourceType.DEFAULT;
			boolean isFromDefaultThunk = FunctionMerge.isDefaultThunk(fromFunc);
			Namespace fromNamespace = // default thunks will lie about their namespace
				isFromDefaultThunk ? fromProgram.getGlobalNamespace()
						: fromSymbol.getParentNamespace();

			Namespace resolveNamespace = resolveNamespace(fromNamespace, conflictSymbolIDMap);
			if ((toFunc != null) && replacePrimary && !fromDefault) {
				// Save "to" function name and namespace.
				String toName = toFunc.getName();
				SourceType toSource = toFunc.getSymbol().getSource();
				boolean toDefault = toSource == SourceType.DEFAULT;
				Namespace toNamespace = toFunc.getParentNamespace();

				// Merging function name into function as primary.
				replaceFunctionSymbol(fromEntryPoint, toEntryPoint, conflictSymbolIDMap, monitor);
				if (!toDefault && !toName.equals(fromName)) {
					// Merge "to" function name and namespace as label.
					addFunctionAsLabel(toEntryPoint, conflictSymbolIDMap, toSymTab, toSource,
						toName, toNamespace, -1L);
				}
			}
			else if (toFunc != null) {
				if (isFromDefaultThunk && FunctionMerge.isDefaultThunk(toFunc)) {
					return;
				}

				if (toFunc.getSymbol().getSource() == SourceType.DEFAULT) {
					// Default "to" function so replace
					replaceFunctionSymbol(fromEntryPoint, toEntryPoint, conflictSymbolIDMap,
						monitor);
				}
				else if (!fromDefault) {
					// No "to" function or not merging primary.
					addFunctionAsLabel(toEntryPoint, conflictSymbolIDMap, toSymTab,
						fromSymbol.getSource(), fromName, resolveNamespace, fromSymbol.getID());
				}
			}
			else if (!isFromDefaultThunk) {
				// No "to" function or not merging primary.
				addFunctionAsLabel(toEntryPoint, conflictSymbolIDMap, toSymTab,
					fromSymbol.getSource(), fromName, resolveNamespace, fromSymbol.getID());
			}
		}
	}
Merges the function symbol at the indicated entry point from the "from" program into the
"to" program. The function is merged  as a regular "label" symbol.
@param fromEntryPoint the entry point address
This address should be derived from the "from" program.
@param replacePrimary true indicates that the primary symbol in the "to" program should be
set to the function symbol if there was one in the "from" program.
@param conflictSymbolIDMap maps the symbol IDs in the "from" program to the symbol IDs
in the "to" program for any symbols (and their associated objects) that were created
with conflict names.
(key = "from" program's symbol ID; value = "to" program's symbol ID)
@param monitor the task monitor for notifying the user of this merge's progress.

@throws InvalidInputException if the function symbol name from the second program isn't valid
@throws DuplicateNameException if a duplicate name is encountered that couldn't be handled
while copying the function symbol.
Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolMerge.java