diff --git a/compiler-rt/CMakeLists.txt b/compiler-rt/CMakeLists.txt --- a/compiler-rt/CMakeLists.txt +++ b/compiler-rt/CMakeLists.txt @@ -43,6 +43,8 @@ mark_as_advanced(COMPILER_RT_BUILD_PROFILE) option(COMPILER_RT_BUILD_MEMPROF "Build memory profiling runtime" ON) mark_as_advanced(COMPILER_RT_BUILD_MEMPROF) +option(COMPILER_RT_BUILD_MIP "Build mip runtime" ON) +mark_as_advanced(COMPILER_RT_BUILD_MIP) option(COMPILER_RT_BUILD_XRAY_NO_PREINIT "Build xray with no preinit patching" OFF) mark_as_advanced(COMPILER_RT_BUILD_XRAY_NO_PREINIT) option(COMPILER_RT_BUILD_ORC "Build ORC runtime" ON) diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake --- a/compiler-rt/cmake/config-ix.cmake +++ b/compiler-rt/cmake/config-ix.cmake @@ -329,6 +329,7 @@ set(ALL_MEMPROF_SUPPORTED_ARCH ${X86_64}) set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC32} ${PPC64} ${MIPS32} ${MIPS64} ${S390X} ${SPARC} ${SPARCV9}) +set(ALL_MIP_SUPPORTED_ARCH ${X86_64} ${ARM32} ${ARM64}) set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64}) set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64} ${MIPS32} ${MIPS64} ${PPC64} ${S390X} ${SPARC} ${SPARCV9}) @@ -400,6 +401,7 @@ set(SANITIZER_COMMON_SUPPORTED_OS osx) set(PROFILE_SUPPORTED_OS osx) + set(MIP_SUPPORTED_OS osx) set(TSAN_SUPPORTED_OS osx) set(XRAY_SUPPORTED_OS osx) set(FUZZER_SUPPORTED_OS osx) @@ -487,6 +489,7 @@ if(DARWIN_${platform}sim_ARCHS) list(APPEND SANITIZER_COMMON_SUPPORTED_OS ${platform}sim) list(APPEND PROFILE_SUPPORTED_OS ${platform}sim) + list(APPEND MIP_SUPPORTED_OS ${platform}sim) list(APPEND TSAN_SUPPORTED_OS ${platform}sim) list(APPEND FUZZER_SUPPORTED_OS ${platform}sim) endif() @@ -513,6 +516,7 @@ if(DARWIN_${platform}_ARCHS) list(APPEND SANITIZER_COMMON_SUPPORTED_OS ${platform}) list(APPEND PROFILE_SUPPORTED_OS ${platform}) + list(APPEND MIP_SUPPORTED_OS ${platform}) list_intersect(DARWIN_${platform}_TSAN_ARCHS DARWIN_${platform}_ARCHS ALL_TSAN_SUPPORTED_ARCH) if(DARWIN_${platform}_TSAN_ARCHS) @@ -565,6 +569,9 @@ list_intersect(PROFILE_SUPPORTED_ARCH ALL_PROFILE_SUPPORTED_ARCH SANITIZER_COMMON_SUPPORTED_ARCH) + list_intersect(MIP_SUPPORTED_ARCH + ALL_MIP_SUPPORTED_ARCH + SANITIZER_COMMON_SUPPORTED_ARCH) list_intersect(TSAN_SUPPORTED_ARCH ALL_TSAN_SUPPORTED_ARCH SANITIZER_COMMON_SUPPORTED_ARCH) @@ -615,6 +622,7 @@ filter_available_targets(HWASAN_SUPPORTED_ARCH ${ALL_HWASAN_SUPPORTED_ARCH}) filter_available_targets(MEMPROF_SUPPORTED_ARCH ${ALL_MEMPROF_SUPPORTED_ARCH}) filter_available_targets(PROFILE_SUPPORTED_ARCH ${ALL_PROFILE_SUPPORTED_ARCH}) + filter_available_targets(MIP_SUPPORTED_ARCH ${ALL_MIP_SUPPORTED_ARCH}) filter_available_targets(TSAN_SUPPORTED_ARCH ${ALL_TSAN_SUPPORTED_ARCH}) filter_available_targets(UBSAN_SUPPORTED_ARCH ${ALL_UBSAN_SUPPORTED_ARCH}) filter_available_targets(SAFESTACK_SUPPORTED_ARCH @@ -731,6 +739,12 @@ set(COMPILER_RT_HAS_PROFILE FALSE) endif() +if (MIP_SUPPORTED_ARCH AND OS_NAME MATCHES "Darwin|Linux|Android") + set(COMPILER_RT_HAS_MIP TRUE) +else() + set(COMPILER_RT_HAS_MIP FALSE) +endif() + if (COMPILER_RT_HAS_SANITIZER_COMMON AND TSAN_SUPPORTED_ARCH AND OS_NAME MATCHES "Darwin|Linux|FreeBSD|Android|NetBSD") set(COMPILER_RT_HAS_TSAN TRUE) diff --git a/compiler-rt/include/mip/MIPData.inc b/compiler-rt/include/mip/MIPData.inc new file mode 100644 --- /dev/null +++ b/compiler-rt/include/mip/MIPData.inc @@ -0,0 +1,80 @@ +//===-- MIPData.inc - machine ir profile runtime structures -------*- C -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains definitions and data structures that are shared between +// the runtime and the compiler. It lives in two locations that need to stay in +// sync. +// + llvm/include/llvm/MIP/MIPData.inc +// + compiler-rt/include/mip/MIPData.inc +// +//===----------------------------------------------------------------------===// + +#ifndef MIP_DATA_DEFINED + +#include + +#ifndef MIP_DATA_INC +#define MIP_DATA_INC + +#define MIP_SIMPLE_QUOTE(x) #x +#define MIP_QUOTE(x) MIP_SIMPLE_QUOTE(x) +#define MIP_SIMPLE_CONCAT(x,y) x ## y +#define MIP_CONCAT(x,y) MIP_SIMPLE_CONCAT(x,y) + +#define MIP_RAW_SECTION __llvm_mipraw +#define MIP_MAP_SECTION __llvm_mipmap +#define MIP_RUNTIME_SYMBOL __llvm_mip_runtime + +#define MIP_RAW_SECTION_NAME MIP_QUOTE(MIP_RAW_SECTION) +#define MIP_MAP_SECTION_NAME MIP_QUOTE(MIP_MAP_SECTION) +#define MIP_RUNTIME_SYMBOL_NAME MIP_QUOTE(MIP_RUNTIME_SYMBOL) + +// MIP magic value in little endian format. +// \251 M I P +// 0xFB 0x4D 0x49 0x50 +#define MIP_MAGIC_VALUE (0x50494DFB) +#define MIP_VERSION (8) + +typedef enum { + MIP_FILE_TYPE_RAW = 1 << 0, // .mipraw + MIP_FILE_TYPE_CALL_EDGE_SAMPLES = 1 << 1, // .mipret + MIP_FILE_TYPE_MAP = 1 << 2, // .mipmap + MIP_FILE_TYPE_PROFILE = 1 << 3, // .mip + MIP_FILE_TYPE_64_BIT = 1 << 4, + MIP_FILE_TYPE_32_BIT = 1 << 5, +} MIPFileType; + +typedef enum { + MIP_PROFILE_TYPE_FUNCTION_COVERAGE = 1 << 0, + MIP_PROFILE_TYPE_BLOCK_COVERAGE = 1 << 1, + MIP_PROFILE_TYPE_FUNCTION_TIMESTAMP = 1 << 2, + MIP_PROFILE_TYPE_FUNCTION_CALL_COUNT = 1 << 3, + MIP_PROFILE_TYPE_RETURN_ADDRESS = 1 << 4, +} MIPProfileType; + +typedef struct { + uint32_t Magic; + uint16_t Version; + uint16_t FileType; + uint32_t ProfileType; + uint32_t ModuleHash; + int64_t RawSectionOffset; + uint32_t Reserved; + uint32_t OffsetToData; +} MIPHeader; + +typedef struct { + uint32_t CalleeProfileDataOffset; + uint32_t SectionRelativeReturnAddress; +} CallEdge_t; + +#endif // MIP_DATA_INC + +#else // MIP_DATA_INC +#undef MIP_DATA_DEFINED +#endif // MIP_DATA_DEFINED diff --git a/compiler-rt/lib/CMakeLists.txt b/compiler-rt/lib/CMakeLists.txt --- a/compiler-rt/lib/CMakeLists.txt +++ b/compiler-rt/lib/CMakeLists.txt @@ -54,6 +54,10 @@ compiler_rt_build_runtime(profile) endif() +if(COMPILER_RT_BUILD_MIP AND COMPILER_RT_HAS_MIP) + compiler_rt_build_runtime(mip) +endif() + if(COMPILER_RT_BUILD_XRAY) compiler_rt_build_runtime(xray) endif() diff --git a/compiler-rt/lib/mip/CMakeLists.txt b/compiler-rt/lib/mip/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/mip/CMakeLists.txt @@ -0,0 +1,31 @@ +add_compiler_rt_component(mip) + +set(MIP_SOURCES + MIPHelper.c + MIPRuntime.cpp +) + +set(MIP_HEADERS + MIPHelper.h +) + +include_directories(../../include) + +if(APPLE) + add_compiler_rt_runtime(clang_rt.mip + STATIC + OS ${MIP_SUPPORTED_OS} + ARCHS ${MIP_SUPPORTED_ARCH} + CFLAGS ${EXTRA_FLAGS} + SOURCES ${MIP_SOURCES} + ADDITIONAL_HEADERS ${MIP_HEADERS} + PARENT_TARGET mip) +else() + add_compiler_rt_runtime(clang_rt.mip + STATIC + ARCHS ${MIP_SUPPORTED_ARCH} + CFLAGS ${EXTRA_FLAGS} + SOURCES ${MIP_SOURCES} + ADDITIONAL_HEADERS ${MIP_HEADERS} + PARENT_TARGET mip) +endif() diff --git a/compiler-rt/lib/mip/MIPHelper.h b/compiler-rt/lib/mip/MIPHelper.h new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/mip/MIPHelper.h @@ -0,0 +1,22 @@ +/*===- MIPHelper.h - Machine IR Profile Runtime Helper --------------------===*\ +|* +|* 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 +|* +\*===----------------------------------------------------------------------===*/ + +#ifndef MIP_MIPHELPER_H +#define MIP_MIPHELPER_H + +#include "mip/MIPData.inc" + +void __llvm_dump_mip_profile(void); +int __llvm_dump_mip_profile_with_filename(const char *Filename); + +void *__llvm_mip_profile_begin(void); +void *__llvm_mip_profile_end(void); + +void __llvm_mip_runtime_initialize(void); + +#endif // MIP_MIPHELPER_H diff --git a/compiler-rt/lib/mip/MIPHelper.c b/compiler-rt/lib/mip/MIPHelper.c new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/mip/MIPHelper.c @@ -0,0 +1,77 @@ +/*===- MIPHelper.c - Machine IR Profile Runtime Helper --------------------===*\ +|* +|* 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 +|* +\*===----------------------------------------------------------------------===*/ + +#include "MIPHelper.h" +#include +#include +#include +#include + +void __llvm_mip_runtime_initialize(void) { atexit(__llvm_dump_mip_profile); } + +void __llvm_dump_mip_profile(void) { + const char *Filename = getenv("LLVM_MIP_PROFILE_FILENAME"); + if (!Filename || !Filename[0]) + Filename = "default.mipraw"; + + char *FormatSpecifierPtr; + char Buffer[strlen(Filename) + 3]; + if ((FormatSpecifierPtr = strstr(Filename, "%h"))) { + const MIPHeader *Header = (MIPHeader *)__llvm_mip_profile_begin(); + const char *Prefix = Filename; + int PrefixLength = FormatSpecifierPtr - Filename; + const char *Suffix = FormatSpecifierPtr + strlen("%h"); + sprintf(Buffer, "%.*s%04x%s", PrefixLength, Prefix, + Header->ModuleHash & 0xFFFF, Suffix); + Filename = Buffer; + } + __llvm_dump_mip_profile_with_filename(Filename); +} + +int __llvm_dump_mip_profile_with_filename(const char *Filename) { + FILE *filep = fopen(Filename, "wb"); + if (!filep) { + fprintf(stderr, "[MIPRuntime]: Failed to open %s: %s\n", Filename, + strerror(errno)); + return -1; + } + + const void *Data = __llvm_mip_profile_begin(); + size_t DataSize = + (char *)__llvm_mip_profile_end() - (char *)__llvm_mip_profile_begin(); + size_t BytesWritten = fwrite(Data, 1, DataSize, filep); + if (BytesWritten != DataSize) { + fprintf(stderr, "[MIPRuntime]: Failed to write to %s: %s\n", Filename, + strerror(errno)); + fclose(filep); + return -1; + } + + fclose(filep); + return 0; +} + +#ifdef __linux__ +#define MIP_RAW_SECTION_BEGIN_SYMBOL MIP_CONCAT(__start_, MIP_RAW_SECTION) +#define MIP_RAW_SECTION_END_SYMBOL MIP_CONCAT(__stop_, MIP_RAW_SECTION) +extern char MIP_RAW_SECTION_BEGIN_SYMBOL; +extern char MIP_RAW_SECTION_END_SYMBOL; +#endif // __linux__ + +#ifdef __APPLE__ +#define MIP_RAW_SECTION_BEGIN_SYMBOL __llvm_mip_raw_section_start +#define MIP_RAW_SECTION_END_SYMBOL __llvm_mip_raw_section_end +extern char MIP_RAW_SECTION_BEGIN_SYMBOL __asm( + "section$start$__DATA$" MIP_RAW_SECTION_NAME); +extern char MIP_RAW_SECTION_END_SYMBOL __asm( + "section$end$__DATA$" MIP_RAW_SECTION_NAME); +#endif // __APPLE__ + +void *__llvm_mip_profile_begin(void) { return &MIP_RAW_SECTION_BEGIN_SYMBOL; } + +void *__llvm_mip_profile_end(void) { return &MIP_RAW_SECTION_END_SYMBOL; } diff --git a/compiler-rt/lib/mip/MIPRuntime.cpp b/compiler-rt/lib/mip/MIPRuntime.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/mip/MIPRuntime.cpp @@ -0,0 +1,23 @@ +/*===- MIPRuntime.c - Machine IR Profile Runtime Helper -------------------===*\ +|* +|* 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 +|* +\*===----------------------------------------------------------------------===*/ + +extern "C" { +#include "MIPHelper.h" +int MIP_RUNTIME_SYMBOL; +} + +namespace { + +class RegisterMIPRuntime { +public: + RegisterMIPRuntime() { __llvm_mip_runtime_initialize(); } +}; + +RegisterMIPRuntime Registration; + +} // namespace