COMPILER_RT_VISIBILITY
int __llvm_profile_write_file(void) {
  int rc;

  GetEnvHook = &getenv;
  /* Check the filename. */
  if (!__llvm_profile_CurrentFilename) {
    PROF_ERR("LLVM Profile: Failed to write file : %s\n", "Filename not set");
    return -1;
  }

  /* Check if there is llvm/runtime version mismatch.  */
  if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
    PROF_ERR("LLVM Profile: runtime and instrumentation version mismatch : "
             "expected %d, but get %d\n",
             INSTR_PROF_RAW_VERSION,
             (int)GET_VERSION(__llvm_profile_get_version()));
    return -1;
  }

  /* Write the file. */
  rc = writeFileWithName(__llvm_profile_CurrentFilename);
  if (rc)
    PROF_ERR("LLVM Profile: Failed to write file \"%s\": %s\n",
            __llvm_profile_CurrentFilename, strerror(errno));
  return rc;
}
/* The public API for writing profile data into the file with name
 * set by previous calls to __llvm_profile_set_filename or
 * __llvm_profile_override_default_filename or
 * __llvm_profile_initialize_file. */
COMPILER_RT_VISIBILITY
int __llvm_profile_write_file(void) {
    int rc, Length;
    const char *Filename;
    char *FilenameBuf;

    Length = getCurFilenameLength();
    FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
    Filename = getCurFilename(FilenameBuf);

    /* Check the filename. */
    if (!Filename) {
        PROF_ERR("Failed to write file : %s\n", "Filename not set");
        return -1;
    }

    /* Check if there is llvm/runtime version mismatch.  */
    if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
        PROF_ERR("Runtime and instrumentation version mismatch : "
                 "expected %d, but get %d\n",
                 INSTR_PROF_RAW_VERSION,
                 (int)GET_VERSION(__llvm_profile_get_version()));
        return -1;
    }

    /* Write profile data to the file. */
    rc = writeFile(Filename);
    if (rc)
        PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno));
    return rc;
}
/* Read profile data in \c ProfileFile and merge with in-memory
   profile counters. Returns -1 if there is fatal error, otheriwse
   0 is returned.
*/
static int doProfileMerging(FILE *ProfileFile) {
    uint64_t ProfileFileSize;
    char *ProfileBuffer;

    if (fseek(ProfileFile, 0L, SEEK_END) == -1) {
        PROF_ERR("Unable to merge profile data, unable to get size: %s\n",
                 strerror(errno));
        return -1;
    }
    ProfileFileSize = ftell(ProfileFile);

    /* Restore file offset.  */
    if (fseek(ProfileFile, 0L, SEEK_SET) == -1) {
        PROF_ERR("Unable to merge profile data, unable to rewind: %s\n",
                 strerror(errno));
        return -1;
    }

    /* Nothing to merge.  */
    if (ProfileFileSize < sizeof(__llvm_profile_header)) {
        if (ProfileFileSize)
            PROF_WARN("Unable to merge profile data: %s\n",
                      "source profile file is too small.");
        return 0;
    }

    ProfileBuffer = mmap(NULL, ProfileFileSize, PROT_READ, MAP_SHARED | MAP_FILE,
                         fileno(ProfileFile), 0);
    if (ProfileBuffer == MAP_FAILED) {
        PROF_ERR("Unable to merge profile data, mmap failed: %s\n",
                 strerror(errno));
        return -1;
    }

    if (__llvm_profile_check_compatibility(ProfileBuffer, ProfileFileSize)) {
        (void)munmap(ProfileBuffer, ProfileFileSize);
        PROF_WARN("Unable to merge profile data: %s\n",
                  "source profile file is not compatible.");
        return 0;
    }

    /* Now start merging */
    __llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize);
    (void)munmap(ProfileBuffer, ProfileFileSize);

    return 0;
}
/* Open the profile data for merging. It opens the file in r+b mode with
 * file locking.  If the file has content which is compatible with the
 * current process, it also reads in the profile data in the file and merge
 * it with in-memory counters. After the profile data is merged in memory,
 * the original profile data is truncated and gets ready for the profile
 * dumper. With profile merging enabled, each executable as well as any of
 * its instrumented shared libraries dump profile data into their own data file.
*/
static FILE *openFileForMerging(const char *ProfileFileName) {
    FILE *ProfileFile;
    int rc;

    ProfileFile = lprofOpenFileEx(ProfileFileName);
    if (!ProfileFile)
        return NULL;

    rc = doProfileMerging(ProfileFile);
    if (rc || COMPILER_RT_FTRUNCATE(ProfileFile, 0L) ||
            fseek(ProfileFile, 0L, SEEK_SET) == -1) {
        PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName,
                 strerror(errno));
        fclose(ProfileFile);
        return NULL;
    }
    fseek(ProfileFile, 0L, SEEK_SET);
    return ProfileFile;
}