Path: blob/main/contrib/llvm-project/compiler-rt/lib/profile/InstrProfilingPlatformFuchsia.c
35233 views
/*===- InstrProfilingPlatformFuchsia.c - Profile data Fuchsia platform ----===*\1|*2|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3|* See https://llvm.org/LICENSE.txt for license information.4|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5|*6\*===----------------------------------------------------------------------===*/7/*8* This file implements the profiling runtime for Fuchsia and defines the9* shared profile runtime interface. Each module (executable or DSO) statically10* links in the whole profile runtime to satisfy the calls from its11* instrumented code. Several modules in the same program might be separately12* compiled and even use different versions of the instrumentation ABI and data13* format. All they share in common is the VMO and the offset, which live in14* exported globals so that exactly one definition will be shared across all15* modules. Each module has its own independent runtime that registers its own16* atexit hook to append its own data into the shared VMO which is published17* via the data sink hook provided by Fuchsia's dynamic linker.18*/1920#if defined(__Fuchsia__)2122#include <inttypes.h>23#include <stdarg.h>24#include <stdbool.h>25#include <stdlib.h>2627#include <zircon/process.h>28#include <zircon/sanitizer.h>29#include <zircon/status.h>30#include <zircon/syscalls.h>3132#include "InstrProfiling.h"33#include "InstrProfilingInternal.h"34#include "InstrProfilingUtil.h"3536/* This variable is an external reference to symbol defined by the compiler. */37COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR;3839COMPILER_RT_VISIBILITY unsigned lprofProfileDumped(void) {40return 1;41}42COMPILER_RT_VISIBILITY void lprofSetProfileDumped(unsigned Value) {}4344static const char ProfileSinkName[] = "llvm-profile";4546static inline void lprofWrite(const char *fmt, ...) {47char s[256];4849va_list ap;50va_start(ap, fmt);51int ret = vsnprintf(s, sizeof(s), fmt, ap);52va_end(ap);5354__sanitizer_log_write(s, ret);55}5657struct lprofVMOWriterCtx {58/* VMO that contains the profile data for this module. */59zx_handle_t Vmo;60/* Current offset within the VMO where data should be written next. */61uint64_t Offset;62};6364static uint32_t lprofVMOWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs,65uint32_t NumIOVecs) {66struct lprofVMOWriterCtx *Ctx = (struct lprofVMOWriterCtx *)This->WriterCtx;6768/* Compute the total length of data to be written. */69size_t Length = 0;70for (uint32_t I = 0; I < NumIOVecs; I++)71Length += IOVecs[I].ElmSize * IOVecs[I].NumElm;7273/* Resize the VMO to ensure there's sufficient space for the data. */74zx_status_t Status = _zx_vmo_set_size(Ctx->Vmo, Ctx->Offset + Length);75if (Status != ZX_OK)76return -1;7778/* Copy the data into VMO. */79for (uint32_t I = 0; I < NumIOVecs; I++) {80size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm;81if (IOVecs[I].Data) {82Status = _zx_vmo_write(Ctx->Vmo, IOVecs[I].Data, Ctx->Offset, Length);83if (Status != ZX_OK)84return -1;85} else if (IOVecs[I].UseZeroPadding) {86/* Resizing the VMO should zero fill. */87}88Ctx->Offset += Length;89}9091/* Record the profile size as a property of the VMO. */92_zx_object_set_property(Ctx->Vmo, ZX_PROP_VMO_CONTENT_SIZE, &Ctx->Offset,93sizeof(Ctx->Offset));9495return 0;96}9798static void initVMOWriter(ProfDataWriter *This, struct lprofVMOWriterCtx *Ctx) {99This->Write = lprofVMOWriter;100This->WriterCtx = Ctx;101}102103/* This method is invoked by the runtime initialization hook104* InstrProfilingRuntime.o if it is linked in. */105COMPILER_RT_VISIBILITY106void __llvm_profile_initialize(void) {107/* Check if there is llvm/runtime version mismatch. */108if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {109lprofWrite("LLVM Profile: runtime and instrumentation version mismatch: "110"expected %d, but got %d\n",111INSTR_PROF_RAW_VERSION,112(int)GET_VERSION(__llvm_profile_get_version()));113return;114}115116const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();117const __llvm_profile_data *DataEnd = __llvm_profile_end_data();118const char *CountersBegin = __llvm_profile_begin_counters();119const char *CountersEnd = __llvm_profile_end_counters();120const uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);121const uint64_t CountersOffset =122sizeof(__llvm_profile_header) + __llvm_write_binary_ids(NULL) + DataSize;123uint64_t CountersSize =124__llvm_profile_get_counters_size(CountersBegin, CountersEnd);125126/* Don't publish a VMO if there are no counters. */127if (!CountersSize)128return;129130zx_status_t Status;131132/* Create a VMO to hold the profile data. */133zx_handle_t Vmo = ZX_HANDLE_INVALID;134Status = _zx_vmo_create(0, ZX_VMO_RESIZABLE, &Vmo);135if (Status != ZX_OK) {136lprofWrite("LLVM Profile: cannot create VMO: %s\n",137_zx_status_get_string(Status));138return;139}140141/* Give the VMO a name that includes the module signature. */142char VmoName[ZX_MAX_NAME_LEN];143snprintf(VmoName, sizeof(VmoName), "%" PRIu64 ".profraw",144lprofGetLoadModuleSignature());145_zx_object_set_property(Vmo, ZX_PROP_NAME, VmoName, strlen(VmoName));146147/* Write the profile data into the mapped region. */148ProfDataWriter VMOWriter;149struct lprofVMOWriterCtx Ctx = {.Vmo = Vmo, .Offset = 0};150initVMOWriter(&VMOWriter, &Ctx);151if (lprofWriteData(&VMOWriter, 0, 0) != 0) {152lprofWrite("LLVM Profile: failed to write data\n");153_zx_handle_close(Vmo);154return;155}156157uint64_t Len = 0;158Status = _zx_vmo_get_size(Vmo, &Len);159if (Status != ZX_OK) {160lprofWrite("LLVM Profile: failed to get the VMO size: %s\n",161_zx_status_get_string(Status));162_zx_handle_close(Vmo);163return;164}165166uintptr_t Mapping;167Status =168_zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0,169Vmo, 0, Len, &Mapping);170if (Status != ZX_OK) {171lprofWrite("LLVM Profile: failed to map the VMO: %s\n",172_zx_status_get_string(Status));173_zx_handle_close(Vmo);174return;175}176177/* Publish the VMO which contains profile data to the system. Note that this178* also consumes the VMO handle. */179__sanitizer_publish_data(ProfileSinkName, Vmo);180181/* Update the profile fields based on the current mapping. */182INSTR_PROF_PROFILE_COUNTER_BIAS_VAR =183(intptr_t)Mapping - (uintptr_t)CountersBegin + CountersOffset;184185/* Return the memory allocated for counters to OS. */186lprofReleaseMemoryPagesToOS((uintptr_t)CountersBegin, (uintptr_t)CountersEnd);187}188189#endif190191192