llvm/compiler-rt/lib/profile/InstrProfilingFile.c

/*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\
|*
|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|* See https://llvm.org/LICENSE.txt for license information.
|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|*
\*===----------------------------------------------------------------------===*/

#if !defined(__Fuchsia__)

#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _MSC_VER
/* For _alloca. */
#include <malloc.h>
#endif
#if defined(_WIN32)
#include "WindowsMMap.h"
/* For _chsize_s */
#include <io.h>
#include <process.h>
#else
#include <sys/file.h>
#include <sys/mman.h>
#include <unistd.h>
#if defined(__linux__)
#include <sys/types.h>
#endif
#endif

#include "InstrProfiling.h"
#include "InstrProfilingInternal.h"
#include "InstrProfilingPort.h"
#include "InstrProfilingUtil.h"

/* From where is profile name specified.
 * The order the enumerators define their
 * precedence. Re-order them may lead to
 * runtime behavior change. */
ProfileNameSpecifier;

static const char *getPNSStr(ProfileNameSpecifier PNS) {}

#define MAX_PID_SIZE
/* Data structure holding the result of parsed filename pattern. */
lprofFilename;

static lprofFilename lprofCurFilename =;

static int ProfileMergeRequested =;
static int getProfileFileSizeForMerging(FILE *ProfileFile,
                                        uint64_t *ProfileFileSize);

#if defined(__APPLE__)
static const int ContinuousModeSupported = 1;
static const int UseBiasVar = 0;
static const char *FileOpenMode = "a+b";
static void *BiasAddr = NULL;
static void *BiasDefaultAddr = NULL;
static void *BitmapBiasAddr = NULL;
static void *BitmapBiasDefaultAddr = NULL;
static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {
  /* Get the sizes of various profile data sections. Taken from
   * __llvm_profile_get_size_for_buffer(). */
  const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
  const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
  const char *CountersBegin = __llvm_profile_begin_counters();
  const char *CountersEnd = __llvm_profile_end_counters();
  const char *BitmapBegin = __llvm_profile_begin_bitmap();
  const char *BitmapEnd = __llvm_profile_end_bitmap();
  const char *NamesBegin = __llvm_profile_begin_names();
  const char *NamesEnd = __llvm_profile_end_names();
  const uint64_t NamesSize = (NamesEnd - NamesBegin) * sizeof(char);
  uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
  uint64_t CountersSize =
      __llvm_profile_get_counters_size(CountersBegin, CountersEnd);
  uint64_t NumBitmapBytes =
      __llvm_profile_get_num_bitmap_bytes(BitmapBegin, BitmapEnd);

  /* Check that the counter, bitmap, and data sections in this image are
   * page-aligned. */
  unsigned PageSize = getpagesize();
  if ((intptr_t)CountersBegin % PageSize != 0) {
    PROF_ERR("Counters section not page-aligned (start = %p, pagesz = %u).\n",
             CountersBegin, PageSize);
    return 1;
  }
  if ((intptr_t)BitmapBegin % PageSize != 0) {
    PROF_ERR("Bitmap section not page-aligned (start = %p, pagesz = %u).\n",
             BitmapBegin, PageSize);
    return 1;
  }
  if ((intptr_t)DataBegin % PageSize != 0) {
    PROF_ERR("Data section not page-aligned (start = %p, pagesz = %u).\n",
             DataBegin, PageSize);
    return 1;
  }

  int Fileno = fileno(File);
  /* Determine how much padding is needed before/after the counters and
   * after the names. */
  uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters,
      PaddingBytesAfterNames, PaddingBytesAfterBitmapBytes,
      PaddingBytesAfterVTable, PaddingBytesAfterVNames;
  __llvm_profile_get_padding_sizes_for_counters(
      DataSize, CountersSize, NumBitmapBytes, NamesSize, /*VTableSize=*/0,
      /*VNameSize=*/0, &PaddingBytesBeforeCounters, &PaddingBytesAfterCounters,
      &PaddingBytesAfterBitmapBytes, &PaddingBytesAfterNames,
      &PaddingBytesAfterVTable, &PaddingBytesAfterVNames);

  uint64_t PageAlignedCountersLength = CountersSize + PaddingBytesAfterCounters;
  uint64_t FileOffsetToCounters = CurrentFileOffset +
                                  sizeof(__llvm_profile_header) + DataSize +
                                  PaddingBytesBeforeCounters;
  void *CounterMmap = mmap((void *)CountersBegin, PageAlignedCountersLength,
                           PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED,
                           Fileno, FileOffsetToCounters);
  if (CounterMmap != CountersBegin) {
    PROF_ERR(
        "Continuous counter sync mode is enabled, but mmap() failed (%s).\n"
        "  - CountersBegin: %p\n"
        "  - PageAlignedCountersLength: %" PRIu64 "\n"
        "  - Fileno: %d\n"
        "  - FileOffsetToCounters: %" PRIu64 "\n",
        strerror(errno), CountersBegin, PageAlignedCountersLength, Fileno,
        FileOffsetToCounters);
    return 1;
  }

  /* Also mmap MCDC bitmap bytes. If there aren't any bitmap bytes, mmap()
   * will fail with EINVAL. */
  if (NumBitmapBytes == 0)
    return 0;

  uint64_t PageAlignedBitmapLength =
      NumBitmapBytes + PaddingBytesAfterBitmapBytes;
  uint64_t FileOffsetToBitmap =
      FileOffsetToCounters + CountersSize + PaddingBytesAfterCounters;
  void *BitmapMmap =
      mmap((void *)BitmapBegin, PageAlignedBitmapLength, PROT_READ | PROT_WRITE,
           MAP_FIXED | MAP_SHARED, Fileno, FileOffsetToBitmap);
  if (BitmapMmap != BitmapBegin) {
    PROF_ERR(
        "Continuous counter sync mode is enabled, but mmap() failed (%s).\n"
        "  - BitmapBegin: %p\n"
        "  - PageAlignedBitmapLength: %" PRIu64 "\n"
        "  - Fileno: %d\n"
        "  - FileOffsetToBitmap: %" PRIu64 "\n",
        strerror(errno), BitmapBegin, PageAlignedBitmapLength, Fileno,
        FileOffsetToBitmap);
    return 1;
  }
  return 0;
}
#elif defined(__ELF__) || defined(_WIN32)

#define INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR
COMPILER_RT_VISIBILITY intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR =;
#define INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR
COMPILER_RT_VISIBILITY intptr_t INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR =;

/* This variable is a weak external reference which could be used to detect
 * whether or not the compiler defined this symbol. */
#if defined(_MSC_VER)
COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR;
COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_BITMAP_BIAS_VAR;
#if defined(_M_IX86) || defined(__i386__)
#define WIN_SYM_PREFIX
#else
#define WIN_SYM_PREFIX
#endif
#pragma comment(                                                               \
    linker, "/alternatename:" WIN_SYM_PREFIX INSTR_PROF_QUOTE(                 \
                INSTR_PROF_PROFILE_COUNTER_BIAS_VAR) "=" WIN_SYM_PREFIX        \
                INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR))
#pragma comment(                                                               \
    linker, "/alternatename:" WIN_SYM_PREFIX INSTR_PROF_QUOTE(                 \
                INSTR_PROF_PROFILE_BITMAP_BIAS_VAR) "=" WIN_SYM_PREFIX         \
                INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR))
#else
COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR
    __attribute__((weak, alias));
COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_BITMAP_BIAS_VAR
    __attribute__((weak, alias));
#endif
static const int ContinuousModeSupported =;
static const int UseBiasVar =;
/* TODO: If there are two DSOs, the second DSO initilization will truncate the
 * first profile file. */
static const char *FileOpenMode =;
/* This symbol is defined by the compiler when runtime counter relocation is
 * used and runtime provides a weak alias so we can check if it's defined. */
static void *BiasAddr =;
static void *BiasDefaultAddr =;
static void *BitmapBiasAddr =;
static void *BitmapBiasDefaultAddr =;
static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {}
#else
static const int ContinuousModeSupported = 0;
static const int UseBiasVar = 0;
static const char *FileOpenMode = "a+b";
static void *BiasAddr = NULL;
static void *BiasDefaultAddr = NULL;
static void *BitmapBiasAddr = NULL;
static void *BitmapBiasDefaultAddr = NULL;
static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {
  return 0;
}
#endif

static int isProfileMergeRequested(void) {}
static void setProfileMergeRequested(int EnableMerge) {}

static FILE *ProfileFile =;
static FILE *getProfileFile(void) {}
static void setProfileFile(FILE *File) {}

static int getCurFilenameLength(void);
static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf);
static unsigned doMerging(void) {}

/* Return 1 if there is an error, otherwise return  0.  */
static uint32_t fileWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs,
                           uint32_t NumIOVecs) {}

/* TODO: make buffer size controllable by an internal option, and compiler can pass the size
   to runtime via a variable. */
static uint32_t orderFileWriter(FILE *File, const uint32_t *DataStart) {}

static void initFileWriter(ProfDataWriter *This, FILE *File) {}

COMPILER_RT_VISIBILITY ProfBufferIO *
lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) {}

static void setupIOBuffer(void) {}

/* Get the size of the profile file. If there are any errors, print the
 * message under the assumption that the profile is being read for merging
 * purposes, and return -1. Otherwise return the file size in the inout param
 * \p ProfileFileSize. */
static int getProfileFileSizeForMerging(FILE *ProfileFile,
                                        uint64_t *ProfileFileSize) {}

/* mmap() \p ProfileFile for profile merging purposes, assuming that an
 * exclusive lock is held on the file and that \p ProfileFileSize is the
 * length of the file. Return the mmap'd buffer in the inout variable
 * \p ProfileBuffer. Returns -1 on failure. On success, the caller is
 * responsible for unmapping the mmap'd buffer in \p ProfileBuffer. */
static int mmapProfileForMerging(FILE *ProfileFile, uint64_t ProfileFileSize,
                                 char **ProfileBuffer) {}

/* Read profile data in \c ProfileFile and merge with in-memory
   profile counters. Returns -1 if there is fatal error, otheriwse
   0 is returned. Returning 0 does not mean merge is actually
   performed. If merge is actually done, *MergeDone is set to 1.
*/
static int doProfileMerging(FILE *ProfileFile, int *MergeDone) {}

/* Create the directory holding the file, if needed. */
static void createProfileDir(const char *Filename) {}

/* 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, int *MergeDone) {}

static FILE *getFileObject(const char *OutputName) {}

/* Write profile data to file \c OutputName.  */
static int writeFile(const char *OutputName) {}

/* Write order data to file \c OutputName.  */
static int writeOrderFile(const char *OutputName) {}

#define LPROF_INIT_ONCE_ENV

static void truncateCurrentFile(void) {}

/* Write a partial profile to \p Filename, which is required to be backed by
 * the open file object \p File. */
static int writeProfileWithFileObject(const char *Filename, FILE *File) {}

static void initializeProfileForContinuousMode(void) {}

static const char *DefaultProfileName =;
static void resetFilenameToDefault(void) {}

static unsigned getMergePoolSize(const char *FilenamePat, int *I) {}

/* Assert that Idx does index past a string null terminator. Return the
 * result of the check. */
static int checkBounds(int Idx, int Strlen) {}

/* Parses the pattern string \p FilenamePat and stores the result to
 * lprofcurFilename structure. */
static int parseFilenamePattern(const char *FilenamePat,
                                unsigned CopyFilenamePat) {}

static void parseAndSetFilename(const char *FilenamePat,
                                ProfileNameSpecifier PNS,
                                unsigned CopyFilenamePat) {}

/* Return buffer length that is required to store the current profile
 * filename with PID and hostname substitutions. */
/* The length to hold uint64_t followed by 3 digits pool id including '_' */
#define SIGLEN
static int getCurFilenameLength(void) {}

/* Return the pointer to the current profile file name (after substituting
 * PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer
 * to store the resulting filename. If no substitution is needed, the
 * current filename pattern string is directly returned, unless ForceUseBuf
 * is enabled. */
static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf) {}

/* Returns the pointer to the environment variable
 * string. Returns null if the env var is not set. */
static const char *getFilenamePatFromEnv(void) {}

COMPILER_RT_VISIBILITY
const char *__llvm_profile_get_path_prefix(void) {}

COMPILER_RT_VISIBILITY
const char *__llvm_profile_get_filename(void) {}

/* This API initializes the file handling, both user specified
 * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE
 * environment variable can override this default value.
 */
COMPILER_RT_VISIBILITY
void __llvm_profile_initialize_file(void) {}

/* This method is invoked by the runtime initialization hook
 * InstrProfilingRuntime.o if it is linked in.
 */
COMPILER_RT_VISIBILITY
void __llvm_profile_initialize(void) {}

/* This API is directly called by the user application code. It has the
 * highest precedence compared with LLVM_PROFILE_FILE environment variable
 * and command line option -fprofile-instr-generate=<profile_name>.
 */
COMPILER_RT_VISIBILITY
void __llvm_profile_set_filename(const char *FilenamePat) {}

/* 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) {}

COMPILER_RT_VISIBILITY
int __llvm_profile_dump(void) {}

/* Order file data will be saved in a file with suffx .order. */
static const char *OrderFileSuffix =;

COMPILER_RT_VISIBILITY
int __llvm_orderfile_write_file(void) {}

COMPILER_RT_VISIBILITY
int __llvm_orderfile_dump(void) {}

static void writeFileWithoutReturn(void) {}

COMPILER_RT_VISIBILITY
int __llvm_profile_register_write_file_atexit(void) {}

COMPILER_RT_VISIBILITY int __llvm_profile_set_file_object(FILE *File,
                                                          int EnableMerge) {}

#endif