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

/*===- InstrProfilingUtil.c - Support library for PGO instrumentation -----===*\
|*
|* 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
|*
\*===----------------------------------------------------------------------===*/

#ifdef _WIN32
#include <direct.h>
#include <process.h>
#include <windows.h>
#include "WindowsMMap.h"
#else
#include <errno.h>
#include <fcntl.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#endif

#ifdef COMPILER_RT_HAS_UNAME
#include <sys/utsname.h>
#endif

#include <stdlib.h>
#include <string.h>

#if defined(__linux__)
#include <signal.h>
#include <sys/prctl.h>
#endif

#if defined(__Fuchsia__)
#include <zircon/process.h>
#include <zircon/syscalls.h>
#endif

#if defined(__FreeBSD__)
#include <signal.h>
#include <sys/procctl.h>
#endif

#include "InstrProfiling.h"
#include "InstrProfilingUtil.h"

COMPILER_RT_VISIBILITY unsigned lprofDirMode =;

COMPILER_RT_VISIBILITY
void __llvm_profile_recursive_mkdir(char *path) {}

COMPILER_RT_VISIBILITY
void __llvm_profile_set_dir_mode(unsigned Mode) {}

COMPILER_RT_VISIBILITY
unsigned __llvm_profile_get_dir_mode(void) {}

#if COMPILER_RT_HAS_ATOMICS != 1
COMPILER_RT_VISIBILITY
uint32_t lprofBoolCmpXchg(void **Ptr, void *OldV, void *NewV) {
  void *R = *Ptr;
  if (R == OldV) {
    *Ptr = NewV;
    return 1;
  }
  return 0;
}
COMPILER_RT_VISIBILITY
void *lprofPtrFetchAdd(void **Mem, long ByteIncr) {
  void *Old = *Mem;
  *((char **)Mem) += ByteIncr;
  return Old;
}

#endif

#ifdef _WIN32
COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) {
  WCHAR Buffer[COMPILER_RT_MAX_HOSTLEN];
  DWORD BufferSize = sizeof(Buffer);
  BOOL Result =
      GetComputerNameExW(ComputerNameDnsFullyQualified, Buffer, &BufferSize);
  if (!Result)
    return -1;
  if (WideCharToMultiByte(CP_UTF8, 0, Buffer, -1, Name, Len, NULL, NULL) == 0)
    return -1;
  return 0;
}
#elif defined(COMPILER_RT_HAS_UNAME)
COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) {}
#endif

COMPILER_RT_VISIBILITY int lprofLockFd(int fd) {}

COMPILER_RT_VISIBILITY int lprofUnlockFd(int fd) {}

COMPILER_RT_VISIBILITY int lprofLockFileHandle(FILE *F) {}

COMPILER_RT_VISIBILITY int lprofUnlockFileHandle(FILE *F) {}

COMPILER_RT_VISIBILITY FILE *lprofOpenFileEx(const char *ProfileName) {}

COMPILER_RT_VISIBILITY const char *lprofGetPathPrefix(int *PrefixStrip,
                                                      size_t *PrefixLen) {}

COMPILER_RT_VISIBILITY void
lprofApplyPathPrefix(char *Dest, const char *PathStr, const char *Prefix,
                     size_t PrefixLen, int PrefixStrip) {}

COMPILER_RT_VISIBILITY const char *
lprofFindFirstDirSeparator(const char *Path) {}

COMPILER_RT_VISIBILITY const char *lprofFindLastDirSeparator(const char *Path) {}

COMPILER_RT_VISIBILITY int lprofSuspendSigKill(void) {}

COMPILER_RT_VISIBILITY void lprofRestoreSigKill(void) {}

COMPILER_RT_VISIBILITY int lprofReleaseMemoryPagesToOS(uintptr_t Begin,
                                                       uintptr_t End) {}

#ifdef _AIX
typedef struct fn_node {
  AtExit_Fn_ptr func;
  struct fn_node *next;
} fn_node;
typedef struct {
  fn_node *top;
} fn_stack;

static void fn_stack_push(fn_stack *, AtExit_Fn_ptr);
static AtExit_Fn_ptr fn_stack_pop(fn_stack *);
/* return 1 if stack is empty, 0 otherwise */
static int fn_stack_is_empty(fn_stack *);

static fn_stack AtExit_stack = {0};
#define ATEXIT_STACK

/* On AIX, atexit() functions registered by a shared library do not get called
 * when the library is dlclose'd, causing a crash when they are eventually
 * called at main program exit. However, a destructor does get called. So we
 * collect all atexit functions registered by profile-rt and at program
 * termination time (normal exit, shared library unload, or dlclose) we walk
 * the list and execute any function that is still sitting in the atexit system
 * queue.
 */
__attribute__((__destructor__)) static void cleanup() {
  while (!fn_stack_is_empty(ATEXIT_STACK)) {
    AtExit_Fn_ptr func = fn_stack_pop(ATEXIT_STACK);
    if (func && unatexit(func) == 0)
      func();
  }
}

static void fn_stack_push(fn_stack *st, AtExit_Fn_ptr func) {
  fn_node *old_top, *n = (fn_node *)malloc(sizeof(fn_node));
  n->func = func;

  while (1) {
    old_top = st->top;
    n->next = old_top;
    if (COMPILER_RT_BOOL_CMPXCHG(&st->top, old_top, n))
      return;
  }
}
static AtExit_Fn_ptr fn_stack_pop(fn_stack *st) {
  fn_node *old_top, *new_top;
  while (1) {
    old_top = st->top;
    if (old_top == 0)
      return 0;
    new_top = old_top->next;
    if (COMPILER_RT_BOOL_CMPXCHG(&st->top, old_top, new_top)) {
      AtExit_Fn_ptr func = old_top->func;
      free(old_top);
      return func;
    }
  }
}

static int fn_stack_is_empty(fn_stack *st) { return st->top == 0; }
#endif

COMPILER_RT_VISIBILITY int lprofAtExit(AtExit_Fn_ptr func) {}