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