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