public FunctionSymbol createMemoryFunctionSymbol(Address addr, String name, Namespace namespace,
			SourceType source) throws IOException, InvalidInputException {

		if (!addr.isMemoryAddress()) {
			throw new IllegalArgumentException("memory address required");
		}

		namespace = validateNamespace(namespace, addr, SymbolType.FUNCTION);
		source = validateSource(source, name, addr, SymbolType.FUNCTION);
		name = validateName(name, source);

		// if there is already a FUNCTION symbol with that name and namespace here, just return it.
		Symbol matching = getSymbol(name, addr, namespace);
		if (matching instanceof FunctionSymbol funcSymbol) {
			return funcSymbol;
		}

		// if there is another function at the same address, throw InvalidInputException
		Symbol primary = getPrimarySymbol(addr);
		if (primary != null && primary.getSymbolType() == SymbolType.FUNCTION) {
			throw new InvalidInputException("Function already exists at: " + addr);
		}

		// See if there is a symbol we want to change into the function symbol
		Symbol symbolToPromote = findSymbolToPromote(matching, primary, source);
		if (symbolToPromote != null && !symbolToPromote.isDynamic()) {
			name = symbolToPromote.getName();
			namespace = symbolToPromote.getParentNamespace();
			source = symbolToPromote.getSource();
		}

		// If promoting a pinned symbol, we need to pin the new function symbol.
		boolean needsPinning = symbolToPromote == null ? false : symbolToPromote.isPinned();

		// delete any promoted symbol, dynamic symbol, and make sure all others are not primary
		cleanUpSymbols(addr, symbolToPromote, primary);

		DBRecord record;
		try {
			record = doCreateBasicSymbolRecord(name, namespace, addr, SymbolType.FUNCTION, true,
				source, false);
			adapter.updateSymbolRecord(record);
		}
		catch (DuplicateNameException e) {
			throw new RuntimeException("Unexpected", e); // duplicate was avoided above
		}

		FunctionSymbol newSymbol = new FunctionSymbol(this, cache, addr, record);

		symbolAdded(newSymbol);

		if (needsPinning) {
			newSymbol.setPinned(true);
		}

		return newSymbol;
	}
Internal method for creating external function symbol.
<p>
NOTE: Any name conflict concerns must be checked before invoking this method. 

@param addr the address for the new symbol
@param name the name of the new symbol
@param namespace the namespace for the new symbol (null may be specified for global
           namespace)
@param source the SourceType of the new symbol
@param externalProgramAddress associated external program memory address (may be null) 
@param originalImportName  original imported name (i.e., mangled name)
@return the new symbol
@throws IOException if IO error occurs
@throws InvalidInputException if the name contains illegal characters (i.e. space)
Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolManager.java