aboutsummaryrefslogtreecommitdiff
path: root/contrib/compiler-rt/lib/profile/InstrProfilingFile.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/compiler-rt/lib/profile/InstrProfilingFile.c')
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfilingFile.c194
1 files changed, 194 insertions, 0 deletions
diff --git a/contrib/compiler-rt/lib/profile/InstrProfilingFile.c b/contrib/compiler-rt/lib/profile/InstrProfilingFile.c
new file mode 100644
index 000000000000..5aef3904b56d
--- /dev/null
+++ b/contrib/compiler-rt/lib/profile/InstrProfilingFile.c
@@ -0,0 +1,194 @@
+/*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfiling.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define UNCONST(ptr) ((void *)(uintptr_t)(ptr))
+
+static int writeFile(FILE *File) {
+ /* Match logic in __llvm_profile_write_buffer(). */
+ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
+ const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
+ const uint64_t *CountersBegin = __llvm_profile_begin_counters();
+ const uint64_t *CountersEnd = __llvm_profile_end_counters();
+ const char *NamesBegin = __llvm_profile_begin_names();
+ const char *NamesEnd = __llvm_profile_end_names();
+
+ /* Calculate size of sections. */
+ const uint64_t DataSize = DataEnd - DataBegin;
+ const uint64_t CountersSize = CountersEnd - CountersBegin;
+ const uint64_t NamesSize = NamesEnd - NamesBegin;
+ const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t);
+
+ /* Enough zeroes for padding. */
+ const char Zeroes[sizeof(uint64_t)] = {0};
+
+ /* Create the header. */
+ uint64_t Header[PROFILE_HEADER_SIZE];
+ Header[0] = __llvm_profile_get_magic();
+ Header[1] = __llvm_profile_get_version();
+ Header[2] = DataSize;
+ Header[3] = CountersSize;
+ Header[4] = NamesSize;
+ Header[5] = (uintptr_t)CountersBegin;
+ Header[6] = (uintptr_t)NamesBegin;
+
+ /* Write the data. */
+#define CHECK_fwrite(Data, Size, Length, File) \
+ do { if (fwrite(Data, Size, Length, File) != Length) return -1; } while (0)
+ CHECK_fwrite(Header, sizeof(uint64_t), PROFILE_HEADER_SIZE, File);
+ CHECK_fwrite(DataBegin, sizeof(__llvm_profile_data), DataSize, File);
+ CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File);
+ CHECK_fwrite(NamesBegin, sizeof(char), NamesSize, File);
+ CHECK_fwrite(Zeroes, sizeof(char), Padding, File);
+#undef CHECK_fwrite
+
+ return 0;
+}
+
+static int writeFileWithName(const char *OutputName) {
+ int RetVal;
+ FILE *OutputFile;
+ if (!OutputName || !OutputName[0])
+ return -1;
+
+ /* Append to the file to support profiling multiple shared objects. */
+ OutputFile = fopen(OutputName, "a");
+ if (!OutputFile)
+ return -1;
+
+ RetVal = writeFile(OutputFile);
+
+ fclose(OutputFile);
+ return RetVal;
+}
+
+__attribute__((weak)) int __llvm_profile_OwnsFilename = 0;
+__attribute__((weak)) const char *__llvm_profile_CurrentFilename = NULL;
+
+static void setFilename(const char *Filename, int OwnsFilename) {
+ if (__llvm_profile_OwnsFilename)
+ free(UNCONST(__llvm_profile_CurrentFilename));
+
+ __llvm_profile_CurrentFilename = Filename;
+ __llvm_profile_OwnsFilename = OwnsFilename;
+}
+
+static void truncateCurrentFile(void) {
+ const char *Filename = __llvm_profile_CurrentFilename;
+ if (!Filename || !Filename[0])
+ return;
+
+ /* Truncate the file. Later we'll reopen and append. */
+ FILE *File = fopen(Filename, "w");
+ if (!File)
+ return;
+ fclose(File);
+}
+
+static void setDefaultFilename(void) { setFilename("default.profraw", 0); }
+
+int getpid(void);
+static int setFilenameFromEnvironment(void) {
+ const char *Filename = getenv("LLVM_PROFILE_FILE");
+ if (!Filename || !Filename[0])
+ return -1;
+
+ /* Check the filename for "%p", which indicates a pid-substitution. */
+#define MAX_PID_SIZE 16
+ char PidChars[MAX_PID_SIZE] = {0};
+ int NumPids = 0;
+ int PidLength = 0;
+ int I;
+ for (I = 0; Filename[I]; ++I)
+ if (Filename[I] == '%' && Filename[++I] == 'p')
+ if (!NumPids++) {
+ PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
+ if (PidLength <= 0)
+ return -1;
+ }
+ if (!NumPids) {
+ setFilename(Filename, 0);
+ return 0;
+ }
+
+ /* Allocate enough space for the substituted filename. */
+ char *Allocated = (char*)malloc(I + NumPids*(PidLength - 2) + 1);
+ if (!Allocated)
+ return -1;
+
+ /* Construct the new filename. */
+ int J;
+ for (I = 0, J = 0; Filename[I]; ++I)
+ if (Filename[I] == '%') {
+ if (Filename[++I] == 'p') {
+ memcpy(Allocated + J, PidChars, PidLength);
+ J += PidLength;
+ }
+ /* Drop any unknown substitutions. */
+ } else
+ Allocated[J++] = Filename[I];
+ Allocated[J] = 0;
+
+ /* Use the computed name. */
+ setFilename(Allocated, 1);
+ return 0;
+}
+
+static void setFilenameAutomatically(void) {
+ if (!setFilenameFromEnvironment())
+ return;
+
+ setDefaultFilename();
+}
+
+__attribute__((visibility("hidden")))
+void __llvm_profile_initialize_file(void) {
+ /* Check if the filename has been initialized. */
+ if (__llvm_profile_CurrentFilename)
+ return;
+
+ /* Detect the filename and truncate. */
+ setFilenameAutomatically();
+ truncateCurrentFile();
+}
+
+__attribute__((visibility("hidden")))
+void __llvm_profile_set_filename(const char *Filename) {
+ setFilename(Filename, 0);
+ truncateCurrentFile();
+}
+
+__attribute__((visibility("hidden")))
+int __llvm_profile_write_file(void) {
+ /* Check the filename. */
+ if (!__llvm_profile_CurrentFilename)
+ return -1;
+
+ /* Write the file. */
+ return writeFileWithName(__llvm_profile_CurrentFilename);
+}
+
+static void writeFileWithoutReturn(void) {
+ __llvm_profile_write_file();
+}
+
+__attribute__((visibility("hidden")))
+int __llvm_profile_register_write_file_atexit(void) {
+ static int HasBeenRegistered = 0;
+
+ if (HasBeenRegistered)
+ return 0;
+
+ HasBeenRegistered = 1;
+ return atexit(writeFileWithoutReturn);
+}