xref: /freebsd/contrib/llvm-project/compiler-rt/lib/profile/InstrProfilingPlatformFuchsia.c (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric /*===- InstrProfilingPlatformFuchsia.c - Profile data Fuchsia platform ----===*\
2*0b57cec5SDimitry Andric |*
3*0b57cec5SDimitry Andric |* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric |* See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric |*
7*0b57cec5SDimitry Andric \*===----------------------------------------------------------------------===*/
8*0b57cec5SDimitry Andric /*
9*0b57cec5SDimitry Andric  * This file implements the profiling runtime for Fuchsia and defines the
10*0b57cec5SDimitry Andric  * shared profile runtime interface. Each module (executable or DSO) statically
11*0b57cec5SDimitry Andric  * links in the whole profile runtime to satisfy the calls from its
12*0b57cec5SDimitry Andric  * instrumented code. Several modules in the same program might be separately
13*0b57cec5SDimitry Andric  * compiled and even use different versions of the instrumentation ABI and data
14*0b57cec5SDimitry Andric  * format. All they share in common is the VMO and the offset, which live in
15*0b57cec5SDimitry Andric  * exported globals so that exactly one definition will be shared across all
16*0b57cec5SDimitry Andric  * modules. Each module has its own independent runtime that registers its own
17*0b57cec5SDimitry Andric  * atexit hook to append its own data into the shared VMO which is published
18*0b57cec5SDimitry Andric  * via the data sink hook provided by Fuchsia's dynamic linker.
19*0b57cec5SDimitry Andric  */
20*0b57cec5SDimitry Andric 
21*0b57cec5SDimitry Andric #if defined(__Fuchsia__)
22*0b57cec5SDimitry Andric 
23*0b57cec5SDimitry Andric #include <inttypes.h>
24*0b57cec5SDimitry Andric #include <stdarg.h>
25*0b57cec5SDimitry Andric #include <stdbool.h>
26*0b57cec5SDimitry Andric #include <stdlib.h>
27*0b57cec5SDimitry Andric 
28*0b57cec5SDimitry Andric #include <zircon/process.h>
29*0b57cec5SDimitry Andric #include <zircon/sanitizer.h>
30*0b57cec5SDimitry Andric #include <zircon/syscalls.h>
31*0b57cec5SDimitry Andric 
32*0b57cec5SDimitry Andric #include "InstrProfiling.h"
33*0b57cec5SDimitry Andric #include "InstrProfilingInternal.h"
34*0b57cec5SDimitry Andric #include "InstrProfilingUtil.h"
35*0b57cec5SDimitry Andric 
36*0b57cec5SDimitry Andric /* VMO that contains the coverage data shared across all modules. This symbol
37*0b57cec5SDimitry Andric  * has default visibility and is exported in each module (executable or DSO)
38*0b57cec5SDimitry Andric  * that statically links in the profiling runtime.
39*0b57cec5SDimitry Andric  */
40*0b57cec5SDimitry Andric zx_handle_t __llvm_profile_vmo;
41*0b57cec5SDimitry Andric /* Current offset within the VMO where data should be written next. This symbol
42*0b57cec5SDimitry Andric  * has default visibility and is exported in each module (executable or DSO)
43*0b57cec5SDimitry Andric  * that statically links in the profiling runtime.
44*0b57cec5SDimitry Andric  */
45*0b57cec5SDimitry Andric uint64_t __llvm_profile_offset;
46*0b57cec5SDimitry Andric 
47*0b57cec5SDimitry Andric static const char ProfileSinkName[] = "llvm-profile";
48*0b57cec5SDimitry Andric 
49*0b57cec5SDimitry Andric static inline void lprofWrite(const char *fmt, ...) {
50*0b57cec5SDimitry Andric   char s[256];
51*0b57cec5SDimitry Andric 
52*0b57cec5SDimitry Andric   va_list ap;
53*0b57cec5SDimitry Andric   va_start(ap, fmt);
54*0b57cec5SDimitry Andric   int ret = vsnprintf(s, sizeof(s), fmt, ap);
55*0b57cec5SDimitry Andric   va_end(ap);
56*0b57cec5SDimitry Andric 
57*0b57cec5SDimitry Andric   __sanitizer_log_write(s, ret + 1);
58*0b57cec5SDimitry Andric }
59*0b57cec5SDimitry Andric 
60*0b57cec5SDimitry Andric static uint32_t lprofVMOWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs,
61*0b57cec5SDimitry Andric                                uint32_t NumIOVecs) {
62*0b57cec5SDimitry Andric   /* Allocate VMO if it hasn't been created yet. */
63*0b57cec5SDimitry Andric   if (__llvm_profile_vmo == ZX_HANDLE_INVALID) {
64*0b57cec5SDimitry Andric     /* Get information about the current process. */
65*0b57cec5SDimitry Andric     zx_info_handle_basic_t Info;
66*0b57cec5SDimitry Andric     zx_status_t Status =
67*0b57cec5SDimitry Andric         _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info,
68*0b57cec5SDimitry Andric                             sizeof(Info), NULL, NULL);
69*0b57cec5SDimitry Andric     if (Status != ZX_OK)
70*0b57cec5SDimitry Andric       return -1;
71*0b57cec5SDimitry Andric 
72*0b57cec5SDimitry Andric     /* Create VMO to hold the profile data. */
73*0b57cec5SDimitry Andric     Status = _zx_vmo_create(0, ZX_VMO_RESIZABLE, &__llvm_profile_vmo);
74*0b57cec5SDimitry Andric     if (Status != ZX_OK)
75*0b57cec5SDimitry Andric       return -1;
76*0b57cec5SDimitry Andric 
77*0b57cec5SDimitry Andric     /* Give the VMO a name including our process KOID so it's easy to spot. */
78*0b57cec5SDimitry Andric     char VmoName[ZX_MAX_NAME_LEN];
79*0b57cec5SDimitry Andric     snprintf(VmoName, sizeof(VmoName), "%s.%" PRIu64, ProfileSinkName,
80*0b57cec5SDimitry Andric              Info.koid);
81*0b57cec5SDimitry Andric     _zx_object_set_property(__llvm_profile_vmo, ZX_PROP_NAME, VmoName,
82*0b57cec5SDimitry Andric                             strlen(VmoName));
83*0b57cec5SDimitry Andric 
84*0b57cec5SDimitry Andric     /* Duplicate the handle since __sanitizer_publish_data consumes it. */
85*0b57cec5SDimitry Andric     zx_handle_t Handle;
86*0b57cec5SDimitry Andric     Status =
87*0b57cec5SDimitry Andric         _zx_handle_duplicate(__llvm_profile_vmo, ZX_RIGHT_SAME_RIGHTS, &Handle);
88*0b57cec5SDimitry Andric     if (Status != ZX_OK)
89*0b57cec5SDimitry Andric       return -1;
90*0b57cec5SDimitry Andric 
91*0b57cec5SDimitry Andric     /* Publish the VMO which contains profile data to the system. */
92*0b57cec5SDimitry Andric     __sanitizer_publish_data(ProfileSinkName, Handle);
93*0b57cec5SDimitry Andric 
94*0b57cec5SDimitry Andric     /* Use the dumpfile symbolizer markup element to write the name of VMO. */
95*0b57cec5SDimitry Andric     lprofWrite("LLVM Profile: {{{dumpfile:%s:%s}}}\n",
96*0b57cec5SDimitry Andric                ProfileSinkName, VmoName);
97*0b57cec5SDimitry Andric   }
98*0b57cec5SDimitry Andric 
99*0b57cec5SDimitry Andric   /* Compute the total length of data to be written. */
100*0b57cec5SDimitry Andric   size_t Length = 0;
101*0b57cec5SDimitry Andric   for (uint32_t I = 0; I < NumIOVecs; I++)
102*0b57cec5SDimitry Andric     Length += IOVecs[I].ElmSize * IOVecs[I].NumElm;
103*0b57cec5SDimitry Andric 
104*0b57cec5SDimitry Andric   /* Resize the VMO to ensure there's sufficient space for the data. */
105*0b57cec5SDimitry Andric   zx_status_t Status =
106*0b57cec5SDimitry Andric       _zx_vmo_set_size(__llvm_profile_vmo, __llvm_profile_offset + Length);
107*0b57cec5SDimitry Andric   if (Status != ZX_OK)
108*0b57cec5SDimitry Andric     return -1;
109*0b57cec5SDimitry Andric 
110*0b57cec5SDimitry Andric   /* Copy the data into VMO. */
111*0b57cec5SDimitry Andric   for (uint32_t I = 0; I < NumIOVecs; I++) {
112*0b57cec5SDimitry Andric     size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm;
113*0b57cec5SDimitry Andric     if (IOVecs[I].Data) {
114*0b57cec5SDimitry Andric       Status = _zx_vmo_write(__llvm_profile_vmo, IOVecs[I].Data,
115*0b57cec5SDimitry Andric                              __llvm_profile_offset, Length);
116*0b57cec5SDimitry Andric       if (Status != ZX_OK)
117*0b57cec5SDimitry Andric         return -1;
118*0b57cec5SDimitry Andric     }
119*0b57cec5SDimitry Andric     __llvm_profile_offset += Length;
120*0b57cec5SDimitry Andric   }
121*0b57cec5SDimitry Andric 
122*0b57cec5SDimitry Andric   return 0;
123*0b57cec5SDimitry Andric }
124*0b57cec5SDimitry Andric 
125*0b57cec5SDimitry Andric static void initVMOWriter(ProfDataWriter *This) {
126*0b57cec5SDimitry Andric   This->Write = lprofVMOWriter;
127*0b57cec5SDimitry Andric   This->WriterCtx = NULL;
128*0b57cec5SDimitry Andric }
129*0b57cec5SDimitry Andric 
130*0b57cec5SDimitry Andric static int dump(void) {
131*0b57cec5SDimitry Andric   if (lprofProfileDumped()) {
132*0b57cec5SDimitry Andric     lprofWrite("Profile data not published: already written.\n");
133*0b57cec5SDimitry Andric     return 0;
134*0b57cec5SDimitry Andric   }
135*0b57cec5SDimitry Andric 
136*0b57cec5SDimitry Andric   /* Check if there is llvm/runtime version mismatch. */
137*0b57cec5SDimitry Andric   if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
138*0b57cec5SDimitry Andric     lprofWrite("Runtime and instrumentation version mismatch : "
139*0b57cec5SDimitry Andric                "expected %d, but got %d\n",
140*0b57cec5SDimitry Andric                INSTR_PROF_RAW_VERSION,
141*0b57cec5SDimitry Andric                (int)GET_VERSION(__llvm_profile_get_version()));
142*0b57cec5SDimitry Andric     return -1;
143*0b57cec5SDimitry Andric   }
144*0b57cec5SDimitry Andric 
145*0b57cec5SDimitry Andric   /* Write the profile data into the mapped region. */
146*0b57cec5SDimitry Andric   ProfDataWriter VMOWriter;
147*0b57cec5SDimitry Andric   initVMOWriter(&VMOWriter);
148*0b57cec5SDimitry Andric   if (lprofWriteData(&VMOWriter, lprofGetVPDataReader(), 0) != 0)
149*0b57cec5SDimitry Andric     return -1;
150*0b57cec5SDimitry Andric 
151*0b57cec5SDimitry Andric   return 0;
152*0b57cec5SDimitry Andric }
153*0b57cec5SDimitry Andric 
154*0b57cec5SDimitry Andric COMPILER_RT_VISIBILITY
155*0b57cec5SDimitry Andric int __llvm_profile_dump(void) {
156*0b57cec5SDimitry Andric   int rc = dump();
157*0b57cec5SDimitry Andric   lprofSetProfileDumped();
158*0b57cec5SDimitry Andric   return rc;
159*0b57cec5SDimitry Andric }
160*0b57cec5SDimitry Andric 
161*0b57cec5SDimitry Andric static void dumpWithoutReturn(void) { dump(); }
162*0b57cec5SDimitry Andric 
163*0b57cec5SDimitry Andric /* This method is invoked by the runtime initialization hook
164*0b57cec5SDimitry Andric  * InstrProfilingRuntime.o if it is linked in.
165*0b57cec5SDimitry Andric  */
166*0b57cec5SDimitry Andric COMPILER_RT_VISIBILITY
167*0b57cec5SDimitry Andric void __llvm_profile_initialize_file(void) {}
168*0b57cec5SDimitry Andric 
169*0b57cec5SDimitry Andric COMPILER_RT_VISIBILITY
170*0b57cec5SDimitry Andric int __llvm_profile_register_write_file_atexit(void) {
171*0b57cec5SDimitry Andric   static bool HasBeenRegistered = false;
172*0b57cec5SDimitry Andric 
173*0b57cec5SDimitry Andric   if (HasBeenRegistered)
174*0b57cec5SDimitry Andric     return 0;
175*0b57cec5SDimitry Andric 
176*0b57cec5SDimitry Andric   lprofSetupValueProfiler();
177*0b57cec5SDimitry Andric 
178*0b57cec5SDimitry Andric   HasBeenRegistered = true;
179*0b57cec5SDimitry Andric   return atexit(dumpWithoutReturn);
180*0b57cec5SDimitry Andric }
181*0b57cec5SDimitry Andric 
182*0b57cec5SDimitry Andric #endif
183