10b57cec5SDimitry Andric /*===- InstrProfilingPlatformFuchsia.c - Profile data Fuchsia platform ----===*\ 20b57cec5SDimitry Andric |* 30b57cec5SDimitry Andric |* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric |* See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric |* 70b57cec5SDimitry Andric \*===----------------------------------------------------------------------===*/ 80b57cec5SDimitry Andric /* 90b57cec5SDimitry Andric * This file implements the profiling runtime for Fuchsia and defines the 100b57cec5SDimitry Andric * shared profile runtime interface. Each module (executable or DSO) statically 110b57cec5SDimitry Andric * links in the whole profile runtime to satisfy the calls from its 120b57cec5SDimitry Andric * instrumented code. Several modules in the same program might be separately 130b57cec5SDimitry Andric * compiled and even use different versions of the instrumentation ABI and data 140b57cec5SDimitry Andric * format. All they share in common is the VMO and the offset, which live in 150b57cec5SDimitry Andric * exported globals so that exactly one definition will be shared across all 160b57cec5SDimitry Andric * modules. Each module has its own independent runtime that registers its own 170b57cec5SDimitry Andric * atexit hook to append its own data into the shared VMO which is published 180b57cec5SDimitry Andric * via the data sink hook provided by Fuchsia's dynamic linker. 190b57cec5SDimitry Andric */ 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric #if defined(__Fuchsia__) 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric #include <inttypes.h> 240b57cec5SDimitry Andric #include <stdarg.h> 250b57cec5SDimitry Andric #include <stdbool.h> 260b57cec5SDimitry Andric #include <stdlib.h> 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric #include <zircon/process.h> 290b57cec5SDimitry Andric #include <zircon/sanitizer.h> 3068d75effSDimitry Andric #include <zircon/status.h> 310b57cec5SDimitry Andric #include <zircon/syscalls.h> 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric #include "InstrProfiling.h" 340b57cec5SDimitry Andric #include "InstrProfilingInternal.h" 350b57cec5SDimitry Andric #include "InstrProfilingUtil.h" 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric /* VMO that contains the coverage data shared across all modules. This symbol 380b57cec5SDimitry Andric * has default visibility and is exported in each module (executable or DSO) 390b57cec5SDimitry Andric * that statically links in the profiling runtime. 400b57cec5SDimitry Andric */ 410b57cec5SDimitry Andric zx_handle_t __llvm_profile_vmo; 420b57cec5SDimitry Andric /* Current offset within the VMO where data should be written next. This symbol 430b57cec5SDimitry Andric * has default visibility and is exported in each module (executable or DSO) 440b57cec5SDimitry Andric * that statically links in the profiling runtime. 450b57cec5SDimitry Andric */ 460b57cec5SDimitry Andric uint64_t __llvm_profile_offset; 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric static const char ProfileSinkName[] = "llvm-profile"; 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric static inline void lprofWrite(const char *fmt, ...) { 510b57cec5SDimitry Andric char s[256]; 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric va_list ap; 540b57cec5SDimitry Andric va_start(ap, fmt); 550b57cec5SDimitry Andric int ret = vsnprintf(s, sizeof(s), fmt, ap); 560b57cec5SDimitry Andric va_end(ap); 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric __sanitizer_log_write(s, ret + 1); 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric 6168d75effSDimitry Andric static void createVMO() { 6268d75effSDimitry Andric /* Don't create VMO if it has been alread created. */ 6368d75effSDimitry Andric if (__llvm_profile_vmo != ZX_HANDLE_INVALID) 6468d75effSDimitry Andric return; 6568d75effSDimitry Andric 660b57cec5SDimitry Andric /* Get information about the current process. */ 670b57cec5SDimitry Andric zx_info_handle_basic_t Info; 680b57cec5SDimitry Andric zx_status_t Status = 690b57cec5SDimitry Andric _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info, 700b57cec5SDimitry Andric sizeof(Info), NULL, NULL); 7168d75effSDimitry Andric if (Status != ZX_OK) { 7268d75effSDimitry Andric lprofWrite("LLVM Profile: cannot get info about current process: %s\n", 7368d75effSDimitry Andric _zx_status_get_string(Status)); 7468d75effSDimitry Andric return; 7568d75effSDimitry Andric } 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric /* Create VMO to hold the profile data. */ 780b57cec5SDimitry Andric Status = _zx_vmo_create(0, ZX_VMO_RESIZABLE, &__llvm_profile_vmo); 7968d75effSDimitry Andric if (Status != ZX_OK) { 8068d75effSDimitry Andric lprofWrite("LLVM Profile: cannot create VMO: %s\n", 8168d75effSDimitry Andric _zx_status_get_string(Status)); 8268d75effSDimitry Andric return; 8368d75effSDimitry Andric } 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric /* Give the VMO a name including our process KOID so it's easy to spot. */ 860b57cec5SDimitry Andric char VmoName[ZX_MAX_NAME_LEN]; 8768d75effSDimitry Andric snprintf(VmoName, sizeof(VmoName), "%s.%" PRIu64, ProfileSinkName, Info.koid); 880b57cec5SDimitry Andric _zx_object_set_property(__llvm_profile_vmo, ZX_PROP_NAME, VmoName, 890b57cec5SDimitry Andric strlen(VmoName)); 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric /* Duplicate the handle since __sanitizer_publish_data consumes it. */ 920b57cec5SDimitry Andric zx_handle_t Handle; 930b57cec5SDimitry Andric Status = 940b57cec5SDimitry Andric _zx_handle_duplicate(__llvm_profile_vmo, ZX_RIGHT_SAME_RIGHTS, &Handle); 9568d75effSDimitry Andric if (Status != ZX_OK) { 9668d75effSDimitry Andric lprofWrite("LLVM Profile: cannot duplicate VMO handle: %s\n", 9768d75effSDimitry Andric _zx_status_get_string(Status)); 9868d75effSDimitry Andric _zx_handle_close(__llvm_profile_vmo); 9968d75effSDimitry Andric __llvm_profile_vmo = ZX_HANDLE_INVALID; 10068d75effSDimitry Andric return; 10168d75effSDimitry Andric } 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric /* Publish the VMO which contains profile data to the system. */ 1040b57cec5SDimitry Andric __sanitizer_publish_data(ProfileSinkName, Handle); 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric /* Use the dumpfile symbolizer markup element to write the name of VMO. */ 10768d75effSDimitry Andric lprofWrite("LLVM Profile: {{{dumpfile:%s:%s}}}\n", ProfileSinkName, VmoName); 1080b57cec5SDimitry Andric } 1090b57cec5SDimitry Andric 11068d75effSDimitry Andric static uint32_t lprofVMOWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs, 11168d75effSDimitry Andric uint32_t NumIOVecs) { 1120b57cec5SDimitry Andric /* Compute the total length of data to be written. */ 1130b57cec5SDimitry Andric size_t Length = 0; 1140b57cec5SDimitry Andric for (uint32_t I = 0; I < NumIOVecs; I++) 1150b57cec5SDimitry Andric Length += IOVecs[I].ElmSize * IOVecs[I].NumElm; 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric /* Resize the VMO to ensure there's sufficient space for the data. */ 1180b57cec5SDimitry Andric zx_status_t Status = 1190b57cec5SDimitry Andric _zx_vmo_set_size(__llvm_profile_vmo, __llvm_profile_offset + Length); 1200b57cec5SDimitry Andric if (Status != ZX_OK) 1210b57cec5SDimitry Andric return -1; 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric /* Copy the data into VMO. */ 1240b57cec5SDimitry Andric for (uint32_t I = 0; I < NumIOVecs; I++) { 1250b57cec5SDimitry Andric size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm; 1260b57cec5SDimitry Andric if (IOVecs[I].Data) { 1270b57cec5SDimitry Andric Status = _zx_vmo_write(__llvm_profile_vmo, IOVecs[I].Data, 1280b57cec5SDimitry Andric __llvm_profile_offset, Length); 1290b57cec5SDimitry Andric if (Status != ZX_OK) 1300b57cec5SDimitry Andric return -1; 131*480093f4SDimitry Andric } else if (IOVecs[I].UseZeroPadding) { 132*480093f4SDimitry Andric /* Resizing the VMO should zero fill. */ 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric __llvm_profile_offset += Length; 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric return 0; 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric static void initVMOWriter(ProfDataWriter *This) { 1410b57cec5SDimitry Andric This->Write = lprofVMOWriter; 1420b57cec5SDimitry Andric This->WriterCtx = NULL; 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric static int dump(void) { 1460b57cec5SDimitry Andric if (lprofProfileDumped()) { 14768d75effSDimitry Andric lprofWrite("LLVM Profile: data not published: already written.\n"); 1480b57cec5SDimitry Andric return 0; 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric /* Check if there is llvm/runtime version mismatch. */ 1520b57cec5SDimitry Andric if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) { 15368d75effSDimitry Andric lprofWrite("LLVM Profile: runtime and instrumentation version mismatch: " 1540b57cec5SDimitry Andric "expected %d, but got %d\n", 1550b57cec5SDimitry Andric INSTR_PROF_RAW_VERSION, 1560b57cec5SDimitry Andric (int)GET_VERSION(__llvm_profile_get_version())); 1570b57cec5SDimitry Andric return -1; 1580b57cec5SDimitry Andric } 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric /* Write the profile data into the mapped region. */ 1610b57cec5SDimitry Andric ProfDataWriter VMOWriter; 1620b57cec5SDimitry Andric initVMOWriter(&VMOWriter); 1630b57cec5SDimitry Andric if (lprofWriteData(&VMOWriter, lprofGetVPDataReader(), 0) != 0) 1640b57cec5SDimitry Andric return -1; 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric return 0; 1670b57cec5SDimitry Andric } 1680b57cec5SDimitry Andric 1690b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 1700b57cec5SDimitry Andric int __llvm_profile_dump(void) { 1710b57cec5SDimitry Andric int rc = dump(); 1720b57cec5SDimitry Andric lprofSetProfileDumped(); 1730b57cec5SDimitry Andric return rc; 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric static void dumpWithoutReturn(void) { dump(); } 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric /* This method is invoked by the runtime initialization hook 1790b57cec5SDimitry Andric * InstrProfilingRuntime.o if it is linked in. 1800b57cec5SDimitry Andric */ 1810b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 18268d75effSDimitry Andric void __llvm_profile_initialize_file(void) { createVMO(); } 1830b57cec5SDimitry Andric 1840b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 1850b57cec5SDimitry Andric int __llvm_profile_register_write_file_atexit(void) { 1860b57cec5SDimitry Andric static bool HasBeenRegistered = false; 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric if (HasBeenRegistered) 1890b57cec5SDimitry Andric return 0; 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric lprofSetupValueProfiler(); 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric HasBeenRegistered = true; 1940b57cec5SDimitry Andric return atexit(dumpWithoutReturn); 1950b57cec5SDimitry Andric } 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric #endif 198