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 40namespace __xray { 41 42#if SANITIZER_FUCHSIA 43constexpr const char* ProfileSinkName = "llvm-xray"; 44 45LogWriter::~LogWriter() { 46 _zx_handle_close(Vmo); 47} 48 49void 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 75void LogWriter::Flush() XRAY_NEVER_INSTRUMENT { 76 // Nothing to do here since WriteAll writes directly into the VMO. 77} 78 79LogWriter *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 127void LogWriter::Close(LogWriter *LW) { 128 LW->~LogWriter(); 129 InternalFree(LW); 130} 131#else // SANITIZER_FUCHSIA 132LogWriter::~LogWriter() { 133 internal_close(Fd); 134} 135 136void 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 154void LogWriter::Flush() XRAY_NEVER_INSTRUMENT { 155 fsync(Fd); 156} 157 158LogWriter *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 190void LogWriter::Close(LogWriter *LW) { 191 LW->~LogWriter(); 192 deallocate(LW); 193} 194#endif // SANITIZER_FUCHSIA 195 196} // namespace __xray 197