1 //===-- xray_utils.cpp ------------------------------------------*- C++ -*-===// 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 is a part of XRay, a dynamic runtime instrumentation system. 10 // 11 //===----------------------------------------------------------------------===// 12 #include "xray_utils.h" 13 14 #include "sanitizer_common/sanitizer_allocator_internal.h" 15 #include "sanitizer_common/sanitizer_common.h" 16 #include "xray_allocator.h" 17 #include "xray_defs.h" 18 #include "xray_flags.h" 19 #include <cstdio> 20 #include <errno.h> 21 #include <fcntl.h> 22 #include <iterator> 23 #include <stdlib.h> 24 #include <sys/types.h> 25 #include <tuple> 26 #include <unistd.h> 27 #include <utility> 28 29 #if SANITIZER_FUCHSIA 30 #include "sanitizer_common/sanitizer_symbolizer_fuchsia.h" 31 32 #include <inttypes.h> 33 #include <zircon/process.h> 34 #include <zircon/sanitizer.h> 35 #include <zircon/status.h> 36 #include <zircon/syscalls.h> 37 #endif 38 39 namespace __xray { 40 41 #if SANITIZER_FUCHSIA 42 constexpr const char* ProfileSinkName = "llvm-xray"; 43 44 LogWriter::~LogWriter() { 45 _zx_handle_close(Vmo); 46 } 47 48 void LogWriter::WriteAll(const char *Begin, const char *End) XRAY_NEVER_INSTRUMENT { 49 if (Begin == End) 50 return; 51 auto TotalBytes = std::distance(Begin, End); 52 53 const size_t PageSize = flags()->xray_page_size_override > 0 54 ? flags()->xray_page_size_override 55 : GetPageSizeCached(); 56 if (RoundUpTo(Offset, PageSize) != RoundUpTo(Offset + TotalBytes, PageSize)) { 57 // Resize the VMO to ensure there's sufficient space for the data. 58 zx_status_t Status = _zx_vmo_set_size(Vmo, Offset + TotalBytes); 59 if (Status != ZX_OK) { 60 Report("Failed to resize VMO: %s\n", _zx_status_get_string(Status)); 61 return; 62 } 63 } 64 65 // Write the data into VMO. 66 zx_status_t Status = _zx_vmo_write(Vmo, Begin, Offset, TotalBytes); 67 if (Status != ZX_OK) { 68 Report("Failed to write: %s\n", _zx_status_get_string(Status)); 69 return; 70 } 71 Offset += TotalBytes; 72 } 73 74 void LogWriter::Flush() XRAY_NEVER_INSTRUMENT { 75 // Nothing to do here since WriteAll writes directly into the VMO. 76 } 77 78 LogWriter *LogWriter::Open() XRAY_NEVER_INSTRUMENT { 79 // Create VMO to hold the profile data. 80 zx_handle_t Vmo; 81 zx_status_t Status = _zx_vmo_create(0, ZX_VMO_RESIZABLE, &Vmo); 82 if (Status != ZX_OK) { 83 Report("XRay: cannot create VMO: %s\n", _zx_status_get_string(Status)); 84 return nullptr; 85 } 86 87 // Get the KOID of the current process to use in the VMO name. 88 zx_info_handle_basic_t Info; 89 Status = _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info, 90 sizeof(Info), NULL, NULL); 91 if (Status != ZX_OK) { 92 Report("XRay: cannot get basic info about current process handle: %s\n", 93 _zx_status_get_string(Status)); 94 return nullptr; 95 } 96 97 // Give the VMO a name including our process KOID so it's easy to spot. 98 char VmoName[ZX_MAX_NAME_LEN]; 99 internal_snprintf(VmoName, sizeof(VmoName), "%s.%zu", ProfileSinkName, 100 Info.koid); 101 _zx_object_set_property(Vmo, ZX_PROP_NAME, VmoName, strlen(VmoName)); 102 103 // Duplicate the handle since __sanitizer_publish_data consumes it and 104 // LogWriter needs to hold onto it. 105 zx_handle_t Handle; 106 Status =_zx_handle_duplicate(Vmo, ZX_RIGHT_SAME_RIGHTS, &Handle); 107 if (Status != ZX_OK) { 108 Report("XRay: cannot duplicate VMO handle: %s\n", 109 _zx_status_get_string(Status)); 110 return nullptr; 111 } 112 113 // Publish the VMO that receives the logging. Note the VMO's contents can 114 // grow and change after publication. The contents won't be read out until 115 // after the process exits. 116 __sanitizer_publish_data(ProfileSinkName, Handle); 117 118 // Use the dumpfile symbolizer markup element to write the name of the VMO. 119 Report("XRay: " FORMAT_DUMPFILE "\n", ProfileSinkName, VmoName); 120 121 LogWriter *LW = reinterpret_cast<LogWriter *>(InternalAlloc(sizeof(LogWriter))); 122 new (LW) LogWriter(Vmo); 123 return LW; 124 } 125 126 void LogWriter::Close(LogWriter *LW) { 127 LW->~LogWriter(); 128 InternalFree(LW); 129 } 130 #else // SANITIZER_FUCHSIA 131 LogWriter::~LogWriter() { 132 internal_close(Fd); 133 } 134 135 void LogWriter::WriteAll(const char *Begin, const char *End) XRAY_NEVER_INSTRUMENT { 136 if (Begin == End) 137 return; 138 auto TotalBytes = std::distance(Begin, End); 139 while (auto Written = write(Fd, Begin, TotalBytes)) { 140 if (Written < 0) { 141 if (errno == EINTR) 142 continue; // Try again. 143 Report("Failed to write; errno = %d\n", errno); 144 return; 145 } 146 TotalBytes -= Written; 147 if (TotalBytes == 0) 148 break; 149 Begin += Written; 150 } 151 } 152 153 void LogWriter::Flush() XRAY_NEVER_INSTRUMENT { 154 fsync(Fd); 155 } 156 157 LogWriter *LogWriter::Open() XRAY_NEVER_INSTRUMENT { 158 // Open a temporary file once for the log. 159 char TmpFilename[256] = {}; 160 char TmpWildcardPattern[] = "XXXXXX"; 161 auto **Argv = GetArgv(); 162 const char *Progname = !Argv ? "(unknown)" : Argv[0]; 163 const char *LastSlash = internal_strrchr(Progname, '/'); 164 165 if (LastSlash != nullptr) 166 Progname = LastSlash + 1; 167 168 int NeededLength = internal_snprintf( 169 TmpFilename, sizeof(TmpFilename), "%s%s.%s", 170 flags()->xray_logfile_base, Progname, TmpWildcardPattern); 171 if (NeededLength > int(sizeof(TmpFilename))) { 172 Report("XRay log file name too long (%d): %s\n", NeededLength, TmpFilename); 173 return nullptr; 174 } 175 int Fd = mkstemp(TmpFilename); 176 if (Fd == -1) { 177 Report("XRay: Failed opening temporary file '%s'; not logging events.\n", 178 TmpFilename); 179 return nullptr; 180 } 181 if (Verbosity()) 182 Report("XRay: Log file in '%s'\n", TmpFilename); 183 184 LogWriter *LW = allocate<LogWriter>(); 185 new (LW) LogWriter(Fd); 186 return LW; 187 } 188 189 void LogWriter::Close(LogWriter *LW) { 190 LW->~LogWriter(); 191 deallocate(LW); 192 } 193 #endif // SANITIZER_FUCHSIA 194 195 } // namespace __xray 196