private Function createFunction(String name, Namespace nameSpace, Address entryPoint,
			AddressSetView body, Function thunkedFunction, SourceType source)
			throws InvalidInputException, OverlappingFunctionException {

		lock.acquire();
		try {
			if (entryPoint == null || !entryPoint.isMemoryAddress()) {
				throw new IllegalArgumentException("Function entryPoint must be a memory address");
			}
			if (body == null || !body.contains(entryPoint)) {
				throw new IllegalArgumentException("Function body must contain the entrypoint");
			}
			if (body.getNumAddresses() > Integer.MAX_VALUE) {
				throw new IllegalArgumentException(
					"Function body size must be <= 0x7fffffff byte addresses");
			}
			if (codeMgr.getDefinedDataAt(entryPoint) != null) {
				throw new IllegalArgumentException(
					"Function entryPoint may not be created on defined data");
			}
			checkSingleAddressSpaceOnly(body);
			if (namespaceMgr.overlapsNamespace(body) != null) {
				throw new OverlappingFunctionException(entryPoint);
			}

			if (StringUtils.isBlank(name) ||
				SymbolUtilities.isReservedDynamicLabelName(name, program.getAddressFactory())) {
				source = SourceType.DEFAULT;
				name = "";
			}

			FunctionDB refFunc = null;
			if (thunkedFunction != null) {

				refFunc = (FunctionDB) getFunctionAt(thunkedFunction.getEntryPoint());
				if (refFunc != thunkedFunction) {
					throw new IllegalArgumentException("thunkedFunction not found within program");
				}
				refFunc.checkDeleted();

				// Handle thunk function
				refFunc = (FunctionDB) getFunctionAt(thunkedFunction.getEntryPoint());
				if (refFunc != thunkedFunction) {
					throw new IllegalArgumentException("thunkedFunction not found within program");
				}

				// Check thunk function name - if name matches thunked function
				// name switch to using DEFAULT name
				if (refFunc.getName().equals(name)) {
					source = SourceType.DEFAULT;
					name = "";
				}
			}

			try {
				Symbol symbol =
					symbolMgr.createMemoryFunctionSymbol(entryPoint, name, nameSpace, source);

				long returnDataTypeId =
					program.getDataTypeManager().getResolvedID(DataType.DEFAULT);

				if (refFunc != null) {

					String oldName = symbol.getName();
					thunkAdapter.createThunkRecord(symbol.getID(), refFunc.getID());

					// Default thunk function name changes dynamically as a result of becoming a thunk
					program.symbolChanged(symbol, ProgramEvent.SYMBOL_RENAMED, entryPoint, symbol,
						oldName, symbol.getName());
				}

				DBRecord rec = adapter.createFunctionRecord(symbol.getID(), returnDataTypeId);

				FunctionDB funcDB = new FunctionDB(this, cache, addrMap, rec);
				namespaceMgr.setBody(funcDB, body);

				program.setObjChanged(ProgramEvent.FUNCTION_ADDED, entryPoint, funcDB, null, null);
				return funcDB;
			}
			catch (IOException e) {
				dbError(e);
			}
			catch (OverlappingNamespaceException e) {
				throw new OverlappingFunctionException(entryPoint, e);
			}
			return null;
		}
		finally {
			lock.release();
		}
	}
Transform an existing external symbol into an external function.
This method should only be invoked by the Function Manager.
The {@link ExternalLocation#getOriginalImportedName() original imported name} will initially 
be null.

@param extSpaceAddr the external space address to use when creating this external.  Any 
other symbol using this address must first be deleted.  Results are unpredictable if this is 
not done.
@param name the external function name
@param nameSpace the external function namespace
@param externalProgramAddress the external program address (may be null)
@param originalImportName the original imported name if different from name (may be null)
@param source the source of this external.
@return external function
@throws InvalidInputException if the name is invalid
Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java