1 /*===- InstrProfilingPlatformFuchsia.c - Profile data Fuchsia platform ----===*\
3 |* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 |* See https://llvm.org/LICENSE.txt for license information.
5 |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 \*===----------------------------------------------------------------------===*/
9 * This file implements the profiling runtime for Fuchsia and defines the
10 * shared profile runtime interface. Each module (executable or DSO) statically
11 * links in the whole profile runtime to satisfy the calls from its
12 * instrumented code. Several modules in the same program might be separately
13 * compiled and even use different versions of the instrumentation ABI and data
14 * format. All they share in common is the VMO and the offset, which live in
15 * exported globals so that exactly one definition will be shared across all
16 * modules. Each module has its own independent runtime that registers its own
17 * atexit hook to append its own data into the shared VMO which is published
18 * via the data sink hook provided by Fuchsia's dynamic linker.
21 #if defined(__Fuchsia__)
28 #include <zircon/process.h>
29 #include <zircon/sanitizer.h>
30 #include <zircon/status.h>
31 #include <zircon/syscalls.h>
33 #include "InstrProfiling.h"
34 #include "InstrProfilingInternal.h"
35 #include "InstrProfilingUtil.h"
37 /* This variable is an external reference to symbol defined by the compiler. */
38 COMPILER_RT_VISIBILITY
extern int64_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR
;
40 COMPILER_RT_VISIBILITY
unsigned lprofProfileDumped(void) {
43 COMPILER_RT_VISIBILITY
void lprofSetProfileDumped(unsigned Value
) {}
45 static const char ProfileSinkName
[] = "llvm-profile";
47 static inline void lprofWrite(const char *fmt
, ...) {
52 int ret
= vsnprintf(s
, sizeof(s
), fmt
, ap
);
55 __sanitizer_log_write(s
, ret
);
58 struct lprofVMOWriterCtx
{
59 /* VMO that contains the profile data for this module. */
61 /* Current offset within the VMO where data should be written next. */
65 static uint32_t lprofVMOWriter(ProfDataWriter
*This
, ProfDataIOVec
*IOVecs
,
67 struct lprofVMOWriterCtx
*Ctx
= (struct lprofVMOWriterCtx
*)This
->WriterCtx
;
69 /* Compute the total length of data to be written. */
71 for (uint32_t I
= 0; I
< NumIOVecs
; I
++)
72 Length
+= IOVecs
[I
].ElmSize
* IOVecs
[I
].NumElm
;
74 /* Resize the VMO to ensure there's sufficient space for the data. */
75 zx_status_t Status
= _zx_vmo_set_size(Ctx
->Vmo
, Ctx
->Offset
+ Length
);
79 /* Copy the data into VMO. */
80 for (uint32_t I
= 0; I
< NumIOVecs
; I
++) {
81 size_t Length
= IOVecs
[I
].ElmSize
* IOVecs
[I
].NumElm
;
83 Status
= _zx_vmo_write(Ctx
->Vmo
, IOVecs
[I
].Data
, Ctx
->Offset
, Length
);
86 } else if (IOVecs
[I
].UseZeroPadding
) {
87 /* Resizing the VMO should zero fill. */
89 Ctx
->Offset
+= Length
;
92 /* Record the profile size as a property of the VMO. */
93 _zx_object_set_property(Ctx
->Vmo
, ZX_PROP_VMO_CONTENT_SIZE
, &Ctx
->Offset
,
99 static void initVMOWriter(ProfDataWriter
*This
, struct lprofVMOWriterCtx
*Ctx
) {
100 This
->Write
= lprofVMOWriter
;
101 This
->WriterCtx
= Ctx
;
104 /* This method is invoked by the runtime initialization hook
105 * InstrProfilingRuntime.o if it is linked in. */
106 COMPILER_RT_VISIBILITY
107 void __llvm_profile_initialize(void) {
108 /* Check if there is llvm/runtime version mismatch. */
109 if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION
) {
110 lprofWrite("LLVM Profile: runtime and instrumentation version mismatch: "
111 "expected %d, but got %d\n",
112 INSTR_PROF_RAW_VERSION
,
113 (int)GET_VERSION(__llvm_profile_get_version()));
117 const __llvm_profile_data
*DataBegin
= __llvm_profile_begin_data();
118 const __llvm_profile_data
*DataEnd
= __llvm_profile_end_data();
119 const char *CountersBegin
= __llvm_profile_begin_counters();
120 const char *CountersEnd
= __llvm_profile_end_counters();
121 const uint64_t DataSize
= __llvm_profile_get_data_size(DataBegin
, DataEnd
);
122 const uint64_t CountersOffset
=
123 sizeof(__llvm_profile_header
) + __llvm_write_binary_ids(NULL
) + DataSize
;
124 uint64_t CountersSize
=
125 __llvm_profile_get_counters_size(CountersBegin
, CountersEnd
);
127 /* Don't publish a VMO if there are no counters. */
133 /* Create a VMO to hold the profile data. */
134 zx_handle_t Vmo
= ZX_HANDLE_INVALID
;
135 Status
= _zx_vmo_create(0, ZX_VMO_RESIZABLE
, &Vmo
);
136 if (Status
!= ZX_OK
) {
137 lprofWrite("LLVM Profile: cannot create VMO: %s\n",
138 _zx_status_get_string(Status
));
142 /* Give the VMO a name that includes the module signature. */
143 char VmoName
[ZX_MAX_NAME_LEN
];
144 snprintf(VmoName
, sizeof(VmoName
), "%" PRIu64
".profraw",
145 lprofGetLoadModuleSignature());
146 _zx_object_set_property(Vmo
, ZX_PROP_NAME
, VmoName
, strlen(VmoName
));
148 /* Write the profile data into the mapped region. */
149 ProfDataWriter VMOWriter
;
150 struct lprofVMOWriterCtx Ctx
= {.Vmo
= Vmo
, .Offset
= 0};
151 initVMOWriter(&VMOWriter
, &Ctx
);
152 if (lprofWriteData(&VMOWriter
, 0, 0) != 0) {
153 lprofWrite("LLVM Profile: failed to write data\n");
154 _zx_handle_close(Vmo
);
159 Status
= _zx_vmo_get_size(Vmo
, &Len
);
160 if (Status
!= ZX_OK
) {
161 lprofWrite("LLVM Profile: failed to get the VMO size: %s\n",
162 _zx_status_get_string(Status
));
163 _zx_handle_close(Vmo
);
169 _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ
| ZX_VM_PERM_WRITE
, 0,
170 Vmo
, 0, Len
, &Mapping
);
171 if (Status
!= ZX_OK
) {
172 lprofWrite("LLVM Profile: failed to map the VMO: %s\n",
173 _zx_status_get_string(Status
));
174 _zx_handle_close(Vmo
);
178 /* Publish the VMO which contains profile data to the system. Note that this
179 * also consumes the VMO handle. */
180 __sanitizer_publish_data(ProfileSinkName
, Vmo
);
182 /* Update the profile fields based on the current mapping. */
183 INSTR_PROF_PROFILE_COUNTER_BIAS_VAR
=
184 (intptr_t)Mapping
- (uintptr_t)CountersBegin
+ CountersOffset
;
186 /* Return the memory allocated for counters to OS. */
187 lprofReleaseMemoryPagesToOS((uintptr_t)CountersBegin
, (uintptr_t)CountersEnd
);