201 lines · cpp
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-exception6//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 <new>24#include <stdlib.h>25#include <sys/types.h>26#include <tuple>27#include <unistd.h>28#include <utility>29 30#if SANITIZER_FUCHSIA31#include "sanitizer_common/sanitizer_symbolizer_markup_constants.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#endif39 40namespace __xray {41 42#if SANITIZER_FUCHSIA43constexpr 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 > 055 ? flags()->xray_page_size_override56 : 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 // Record the data size as a property of the VMO.75 _zx_object_set_property(Vmo, ZX_PROP_VMO_CONTENT_SIZE,76 &Offset, sizeof(Offset));77}78 79void LogWriter::Flush() XRAY_NEVER_INSTRUMENT {80 // Nothing to do here since WriteAll writes directly into the VMO.81}82 83LogWriter *LogWriter::Open() XRAY_NEVER_INSTRUMENT {84 // Create VMO to hold the profile data.85 zx_handle_t Vmo;86 zx_status_t Status = _zx_vmo_create(0, ZX_VMO_RESIZABLE, &Vmo);87 if (Status != ZX_OK) {88 Report("XRay: cannot create VMO: %s\n", _zx_status_get_string(Status));89 return nullptr;90 }91 92 // Get the KOID of the current process to use in the VMO name.93 zx_info_handle_basic_t Info;94 Status = _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info,95 sizeof(Info), NULL, NULL);96 if (Status != ZX_OK) {97 Report("XRay: cannot get basic info about current process handle: %s\n",98 _zx_status_get_string(Status));99 return nullptr;100 }101 102 // Give the VMO a name including our process KOID so it's easy to spot.103 char VmoName[ZX_MAX_NAME_LEN];104 internal_snprintf(VmoName, sizeof(VmoName), "%s.%zu", ProfileSinkName,105 Info.koid);106 _zx_object_set_property(Vmo, ZX_PROP_NAME, VmoName, strlen(VmoName));107 108 // Duplicate the handle since __sanitizer_publish_data consumes it and109 // LogWriter needs to hold onto it.110 zx_handle_t Handle;111 Status =_zx_handle_duplicate(Vmo, ZX_RIGHT_SAME_RIGHTS, &Handle);112 if (Status != ZX_OK) {113 Report("XRay: cannot duplicate VMO handle: %s\n",114 _zx_status_get_string(Status));115 return nullptr;116 }117 118 // Publish the VMO that receives the logging. Note the VMO's contents can119 // grow and change after publication. The contents won't be read out until120 // after the process exits.121 __sanitizer_publish_data(ProfileSinkName, Handle);122 123 // Use the dumpfile symbolizer markup element to write the name of the VMO.124 Report("XRay: " FORMAT_DUMPFILE "\n", ProfileSinkName, VmoName);125 126 LogWriter *LW = reinterpret_cast<LogWriter *>(InternalAlloc(sizeof(LogWriter)));127 new (LW) LogWriter(Vmo);128 return LW;129}130 131void LogWriter::Close(LogWriter *LW) {132 LW->~LogWriter();133 InternalFree(LW);134}135#else // SANITIZER_FUCHSIA136LogWriter::~LogWriter() {137 internal_close(Fd);138}139 140void LogWriter::WriteAll(const char *Begin, const char *End) XRAY_NEVER_INSTRUMENT {141 if (Begin == End)142 return;143 auto TotalBytes = std::distance(Begin, End);144 while (auto Written = write(Fd, Begin, TotalBytes)) {145 if (Written < 0) {146 if (errno == EINTR)147 continue; // Try again.148 Report("Failed to write; errno = %d\n", errno);149 return;150 }151 TotalBytes -= Written;152 if (TotalBytes == 0)153 break;154 Begin += Written;155 }156}157 158void LogWriter::Flush() XRAY_NEVER_INSTRUMENT {159 fsync(Fd);160}161 162LogWriter *LogWriter::Open() XRAY_NEVER_INSTRUMENT {163 // Open a temporary file once for the log.164 char TmpFilename[256] = {};165 char TmpWildcardPattern[] = "XXXXXX";166 auto **Argv = GetArgv();167 const char *Progname = !Argv ? "(unknown)" : Argv[0];168 const char *LastSlash = internal_strrchr(Progname, '/');169 170 if (LastSlash != nullptr)171 Progname = LastSlash + 1;172 173 int NeededLength = internal_snprintf(174 TmpFilename, sizeof(TmpFilename), "%s%s.%s",175 flags()->xray_logfile_base, Progname, TmpWildcardPattern);176 if (NeededLength > int(sizeof(TmpFilename))) {177 Report("XRay log file name too long (%d): %s\n", NeededLength, TmpFilename);178 return nullptr;179 }180 int Fd = mkstemp(TmpFilename);181 if (Fd == -1) {182 Report("XRay: Failed opening temporary file '%s'; not logging events.\n",183 TmpFilename);184 return nullptr;185 }186 if (Verbosity())187 Report("XRay: Log file in '%s'\n", TmpFilename);188 189 LogWriter *LW = allocate<LogWriter>();190 new (LW) LogWriter(Fd);191 return LW;192}193 194void LogWriter::Close(LogWriter *LW) {195 LW->~LogWriter();196 deallocate(LW);197}198#endif // SANITIZER_FUCHSIA199 200} // namespace __xray201