InstrProfilingPlatformFuchsia.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*===- InstrProfilingPlatformFuchsia.c - Profile data Fuchsia platform ----===*\
  2. |*
  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
  6. |*
  7. \*===----------------------------------------------------------------------===*/
  8. /*
  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.
  19. */
  20. #if defined(__Fuchsia__)
  21. #include <inttypes.h>
  22. #include <stdarg.h>
  23. #include <stdbool.h>
  24. #include <stdlib.h>
  25. #error #include <zircon/process.h>
  26. #error #include <zircon/sanitizer.h>
  27. #error #include <zircon/status.h>
  28. #error #include <zircon/syscalls.h>
  29. #include "InstrProfiling.h"
  30. #include "InstrProfilingInternal.h"
  31. #include "InstrProfilingUtil.h"
  32. /* This variable is an external reference to symbol defined by the compiler. */
  33. COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR;
  34. COMPILER_RT_VISIBILITY unsigned lprofProfileDumped(void) {
  35. return 1;
  36. }
  37. COMPILER_RT_VISIBILITY void lprofSetProfileDumped(unsigned Value) {}
  38. static const char ProfileSinkName[] = "llvm-profile";
  39. static inline void lprofWrite(const char *fmt, ...) {
  40. char s[256];
  41. va_list ap;
  42. va_start(ap, fmt);
  43. int ret = vsnprintf(s, sizeof(s), fmt, ap);
  44. va_end(ap);
  45. __sanitizer_log_write(s, ret);
  46. }
  47. struct lprofVMOWriterCtx {
  48. /* VMO that contains the profile data for this module. */
  49. zx_handle_t Vmo;
  50. /* Current offset within the VMO where data should be written next. */
  51. uint64_t Offset;
  52. };
  53. static uint32_t lprofVMOWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs,
  54. uint32_t NumIOVecs) {
  55. struct lprofVMOWriterCtx *Ctx = (struct lprofVMOWriterCtx *)This->WriterCtx;
  56. /* Compute the total length of data to be written. */
  57. size_t Length = 0;
  58. for (uint32_t I = 0; I < NumIOVecs; I++)
  59. Length += IOVecs[I].ElmSize * IOVecs[I].NumElm;
  60. /* Resize the VMO to ensure there's sufficient space for the data. */
  61. zx_status_t Status = _zx_vmo_set_size(Ctx->Vmo, Ctx->Offset + Length);
  62. if (Status != ZX_OK)
  63. return -1;
  64. /* Copy the data into VMO. */
  65. for (uint32_t I = 0; I < NumIOVecs; I++) {
  66. size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm;
  67. if (IOVecs[I].Data) {
  68. Status = _zx_vmo_write(Ctx->Vmo, IOVecs[I].Data, Ctx->Offset, Length);
  69. if (Status != ZX_OK)
  70. return -1;
  71. } else if (IOVecs[I].UseZeroPadding) {
  72. /* Resizing the VMO should zero fill. */
  73. }
  74. Ctx->Offset += Length;
  75. }
  76. /* Record the profile size as a property of the VMO. */
  77. _zx_object_set_property(Ctx->Vmo, ZX_PROP_VMO_CONTENT_SIZE, &Ctx->Offset,
  78. sizeof(Ctx->Offset));
  79. return 0;
  80. }
  81. static void initVMOWriter(ProfDataWriter *This, struct lprofVMOWriterCtx *Ctx) {
  82. This->Write = lprofVMOWriter;
  83. This->WriterCtx = Ctx;
  84. }
  85. /* This method is invoked by the runtime initialization hook
  86. * InstrProfilingRuntime.o if it is linked in. */
  87. COMPILER_RT_VISIBILITY
  88. void __llvm_profile_initialize(void) {
  89. /* Check if there is llvm/runtime version mismatch. */
  90. if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
  91. lprofWrite("LLVM Profile: runtime and instrumentation version mismatch: "
  92. "expected %d, but got %d\n",
  93. INSTR_PROF_RAW_VERSION,
  94. (int)GET_VERSION(__llvm_profile_get_version()));
  95. return;
  96. }
  97. const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
  98. const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
  99. const char *CountersBegin = __llvm_profile_begin_counters();
  100. const char *CountersEnd = __llvm_profile_end_counters();
  101. const uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
  102. const uint64_t CountersOffset =
  103. sizeof(__llvm_profile_header) + __llvm_write_binary_ids(NULL) + DataSize;
  104. uint64_t CountersSize =
  105. __llvm_profile_get_counters_size(CountersBegin, CountersEnd);
  106. /* Don't publish a VMO if there are no counters. */
  107. if (!CountersSize)
  108. return;
  109. zx_status_t Status;
  110. /* Create a VMO to hold the profile data. */
  111. zx_handle_t Vmo = ZX_HANDLE_INVALID;
  112. Status = _zx_vmo_create(0, ZX_VMO_RESIZABLE, &Vmo);
  113. if (Status != ZX_OK) {
  114. lprofWrite("LLVM Profile: cannot create VMO: %s\n",
  115. _zx_status_get_string(Status));
  116. return;
  117. }
  118. /* Give the VMO a name that includes the module signature. */
  119. char VmoName[ZX_MAX_NAME_LEN];
  120. snprintf(VmoName, sizeof(VmoName), "%" PRIu64 ".profraw",
  121. lprofGetLoadModuleSignature());
  122. _zx_object_set_property(Vmo, ZX_PROP_NAME, VmoName, strlen(VmoName));
  123. /* Write the profile data into the mapped region. */
  124. ProfDataWriter VMOWriter;
  125. struct lprofVMOWriterCtx Ctx = {.Vmo = Vmo, .Offset = 0};
  126. initVMOWriter(&VMOWriter, &Ctx);
  127. if (lprofWriteData(&VMOWriter, 0, 0) != 0) {
  128. lprofWrite("LLVM Profile: failed to write data\n");
  129. _zx_handle_close(Vmo);
  130. return;
  131. }
  132. uint64_t Len = 0;
  133. Status = _zx_vmo_get_size(Vmo, &Len);
  134. if (Status != ZX_OK) {
  135. lprofWrite("LLVM Profile: failed to get the VMO size: %s\n",
  136. _zx_status_get_string(Status));
  137. _zx_handle_close(Vmo);
  138. return;
  139. }
  140. uintptr_t Mapping;
  141. Status =
  142. _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0,
  143. Vmo, 0, Len, &Mapping);
  144. if (Status != ZX_OK) {
  145. lprofWrite("LLVM Profile: failed to map the VMO: %s\n",
  146. _zx_status_get_string(Status));
  147. _zx_handle_close(Vmo);
  148. return;
  149. }
  150. /* Publish the VMO which contains profile data to the system. Note that this
  151. * also consumes the VMO handle. */
  152. __sanitizer_publish_data(ProfileSinkName, Vmo);
  153. /* Update the profile fields based on the current mapping. */
  154. INSTR_PROF_PROFILE_COUNTER_BIAS_VAR =
  155. (intptr_t)Mapping - (uintptr_t)CountersBegin + CountersOffset;
  156. /* Return the memory allocated for counters to OS. */
  157. lprofReleaseMemoryPagesToOS((uintptr_t)CountersBegin, (uintptr_t)CountersEnd);
  158. }
  159. #endif